如何在实现为二进制堆的优先级队列中保留相同优先级元素的顺序?

Posted

技术标签:

【中文标题】如何在实现为二进制堆的优先级队列中保留相同优先级元素的顺序?【英文标题】:How to preserve the order of elements of the same priority in a priority queue implemented as binary heap? 【发布时间】:2011-10-18 02:04:15 【问题描述】:

我创建了一个二进制堆,它代表一个优先级队列。这只是经典的众所周知的算法。这个堆调度不同事件的时间序列(排序键是时间)。

它支持两种操作:插入和删除。堆的每个节点的键都大于或等于它的每个子节点。但是,添加具有相同键的事件并不会保留它们添加的顺序,因为每次调用 Remove 或 Insert 后,heap-up 和 heap-down 过程都会破坏顺序。

我的问题是:在经典算法中应该改变什么来保持具有相同优先级的节点的顺序?

【问题讨论】:

假设您添加一个新元素,其优先级已经存在.. 会是什么顺序? 添加另一个称为插入顺序(long long)的字段,并且在插入时始终递增。所以你最终得到了最终键的配对:优先级+插入顺序 【参考方案1】:

如果元素按时间顺序插入并且保持此顺序(例如,通过使用“append”而不是“insert”和“remove_and_pack”而不仅仅是“remove”),您可以使用内存地址(强制转换为元素的无符号 32 位或 64 位整数,具体取决于环境)作为最终比较步骤。早期元素的地址在数字上将低于后面的元素。

【讨论】:

【参考方案2】:

据我所知,堆从来不是为了保持顺序而构建的(这就是为什么“堆排序”因是一种稳定的排序而引人注目)。

我知道您要问的是一个小的算法技巧是否能够改变这一点(这不是旧的可靠“时间戳”解决方案)。我觉得不可能。

我会建议的是这个的一些版本:

保持相同的“插入”;

修改“删除”,以确保给定优先级的元素具有一定的顺序。

要做到这一点,在堆下,而不是向下交换元素直到保留顺序:向下交换一个元素,直到它作为相同值元素的树状结构的结束,总是选择向右移动你可以。

不幸的是,这样做的问题是您不知道 insert 会将给定优先级的元素添加到哪里:它可能会在树中的任何位置结束。我相信,改变这一点不仅仅是对结构的调整。

【讨论】:

这是一个有趣的问题,值得进一步研究(我会的)。 其实这个已经问过了:cstheory.stackexchange.com/questions/593/is-there-a-stable-heap【参考方案3】:

一种解决方案是将插入时间属性添加到插入的元素。每次将新元素插入堆时,这可能只是一个简单的计数器递增。然后当两个元素的优先级相等时,比较插入的时间。

【讨论】:

"那么当两个元素的优先级相等时,比较插入的时间。" --- 但我可以拥有更多的只有两个具有相同键的元素。比较它们需要遍历二叉树! @psihodelia:不。在您的实现中,当您插入或删除元素时,必须比较优先级。只需通过比较优先级和时间戳来扩展此比较。

以上是关于如何在实现为二进制堆的优先级队列中保留相同优先级元素的顺序?的主要内容,如果未能解决你的问题,请参考以下文章

线性表--优先队列

线性表--优先队列

为什么优先级队列是使用堆实现的,当我们可以更有效地使用向量实现它时

优先级队列(堆)

优先级队列(堆)

优先级队列(堆)