C++ 从使用链表实现的队列中弹出max节点的最有效方法?C++;

C++ 从使用链表实现的队列中弹出max节点的最有效方法?C++;,c++,linked-list,queue,max,C++,Linked List,Queue,Max,如果使用链表实现fifo队列,那么弹出具有最高值的节点的最有效方法是什么 Mergesort将是O(n log n)。 扫描列表将是O(n) 有人能提出更有效的方法吗 队列必须保留fifo顺序,该顺序以通常的方式进行排队和出列,但有一个额外的方法,如popMax,它弹出并返回具有最高值的节点 不需要代码,只需要一些想法!谢谢 将popMax从O(N)更改为O(logN)是否足够频繁,从而证明了额外存储(每个节点:两个指针加一个索引)和额外复杂性的合理性和将入队和出队从O(1)更改为O(logN)

如果使用链表实现fifo队列,那么弹出具有最高值的节点的最有效方法是什么

Mergesort将是O(n log n)。 扫描列表将是O(n)

有人能提出更有效的方法吗

队列必须保留fifo顺序,该顺序以通常的方式进行排队和出列,但有一个额外的方法,如popMax,它弹出并返回具有最高值的节点


不需要代码,只需要一些想法!谢谢

将popMax从O(N)更改为O(logN)是否足够频繁,从而证明了额外存储(每个节点:两个指针加一个索引)和额外复杂性的合理性将入队和出队从O(1)更改为O(logN)

在我多次解决这个问题的过程中(出于不同的原因和不同的雇主),上述问题的答案始终是“是”。但对你来说可能是“不”。所以首先做出决定

O(N)的任何改进都需要能够从主序列的中间移除。如果主序列是一个只向前的链表,那么现在它需要两个方向的链接:一个额外的指针

指针堆需要另一个额外的指针(每个节点,但不在节点中)。但是,出列需要能够从堆的中间移除,这会将节点内的索引作为指向其在堆中位置的反向指针

如果值得这么做,您可以很容易地找到priorityQueue/heap模板版本的(在线免费)源代码,并且应该清楚地知道如何使堆、对象成为
node*
,并且提供给堆的
less
函数比较指向的节点内的值

接下来,您将更改堆源代码(这是您不简单使用std::priority_queue的原因),这样每当它在队列中定位一个“对象”(意思是
节点*
)时,它都会执行某种回调来通知对象它的新索引

您还需要公开堆代码的一些内部代码。在任何合适版本的堆代码中都有一个点,即代码通过检查堆的最后一个元素是否可以正确地移动到那里(如果是这样做的话),来处理堆中索引x处的洞(缺少元素)或者,如果没有将孔的正确子项移动到孔中,并重复该子项所在的新孔。通常,该代码不会向以x作为输入的外部调用者公开。但它很容易暴露。您的
dequeue
函数需要这样做,才能从堆中删除从列表中删除的相同元素

用于更少的额外存储,但可能需要更多的执行时间(尽管每个函数仍然是O(logN))。您可以有一堆节点,而不是一堆
节点*
。这就是编码这种堆的原因,您应该一般地对notify回调进行编码(类似于
less
)。然后,您的双链接列表具有索引而不是指针(因此增长是健壮的),notify函数更新前一个索引的前向索引和后一个索引的后向索引。为了避免大量特殊的大小写,您需要有一个完整的双链接圆(可能包括一个虚拟节点),而不仅仅是端到端


我自己还没有研究过这些细节(因为在C++11之后的世界中,我从来没有重做过这些),但是我认为一个比上面讨论的notify函数更优雅的替代方法是将对象(将在堆中)包装在一个允许移动但不允许复制的包装器中。由notify执行的操作将在移动过程中执行。这使得std::priority_队列更接近您所需要的,但据我所知,它仍然没有公开代码中用于填充任意位置的漏洞的关键内部点

“需要节点代码”不,你先显示你的。我们不是代码编写服务!您可能有两个列表,一个用于fifo,一个用于max。定义您所指的最高效。时间还是空间?最终的答案取决于您将如何使用它。对于基本的需求组合(在我的职业生涯中经常出现令人惊讶的情况),我总是为自己的节点指针优先级队列(heap)编写代码,并让一个节点成员保存堆位置的索引。然后可以访问任意一个结构来选择要从这两个结构中删除的项。@Jarod42,两个列表将是毫无意义的,您正在添加复杂性和存储,不是为了节省任何时间,而是为了将时间从
popMax
移动到
enqueue
对不起,如果添加更多详细信息,是的,节点已经有两个点(上一个和下一个),这是双重的。它还有两个int,ID和priority(按优先级排序),因此最优雅的解决方案是将节点本身存储在堆中(按优先级排序),并使用C++11移动语义在节点在堆中移动时触发指针修复。再次抱歉!尽量避免使用任何STL,因为STL堆或优先级队列无法公开所需的密钥内部方法。因此,无论如何,您都需要从头重写std::priority_队列的重要部分。但是,如果您知道“heap”是什么意思(而不是malloc的意思),那么这只不过是一小部分简单的代码。