如何更新堆中的元素? (优先队列)

时间:2017-10-29 01:31:52

标签: algorithm priority-queue insert-update min-heap

使用最小/最大堆算法时,优先级可能会发生变化。处理此问题的一种方法是删除并插入元素以更新队列顺序。

对于使用数组实现的优先级队列,这可能是一个似乎可以避免的性能瓶颈,尤其是在优先级变化很小的情况下。

Even if this is not a standard operation for a priority queue,这是一个自定义实现,可以根据我的需要进行修改。

是否有众所周知的最佳实践方法来更新min / max-heap中的元素?

背景信息:我不是二叉树专家,我继承了一些在优先级队列中重新插入元素的性能瓶颈的代码。我为重新排序新元素的min-heap做了一个重新插入函数 - 这给了一个可测量的改进(删除和插入),但这似乎是其他人可能已经解决的问题优雅的方式。

我可以链接到代码,如果它有帮助,但宁愿不太关注实现细节 - 因为这个Q& A可能保持一般。

2 个答案:

答案 0 :(得分:17)

典型解决方案

通常的解决方案是将元素标记为无效并插入新元素,然后在弹出时删除无效条目。

替代解决方案

如果该方法不够,只要知道要更改的值的位置,就可以在O(log n)步骤中恢复min-heap不变量。

回想一下,使用两个原语“siftup”和“siftdown”来构建和维护min-heap(尽管各种来源对于哪个来源有不同的意见,哪些是关闭的)。其中一个将值推到树下,另一个将它们向上浮动。

案例1:价值增加

如果新值 x1 大于旧值 x0 ,则只需要修复 x 下的树,因为{{ 1}}。只需 x x 与其两个子项中较小的一个交换为 x ,而 x 大于其中一个子< /强>

案例2:价值降低

如果新值 x1 小于旧值 x x 下面的树不需要调整,因为parent(x) <= x0 < x1 。相反,我们只需向上移动,将 x 与其父级进行交换,而 x 小于其父级。不需要考虑兄弟节点,因为它们已经大于或等于可能被较低值替换的父节点。

案例3:价值不变

无需工作。现有的不变量没有变化。

Python中的工作代码

测试1,000,000次试验:创建一个随机堆。更改随机选择的值。恢复堆条件。验证结果是否为最小堆。

x1 < x0 <= either_child(x)

答案 1 :(得分:2)

发布自己问题的答案,因为它包含指向工作代码的链接。

事实上这很简单。

通常,min-heap实现具有排序功能see example: BubbleUp/Down

这些函数可以在修改的元素上运行,具体取决于相对于当前值的更改。例如:

if new_value < old_value {
    heap_bubble_up(heap, node);
} else if new_value > old_value {
    heap_bubble_down(heap, node);
}

虽然操作次数取决于值的分布,但这将等于或少于维护排序列表的步骤。

通常,较小的更改比删除+插入更有效。

查看工作codetest,它实现了带有insert / remove / re-prioritize的最小堆,没有初始查找(调用者存储不透明引用)。

即使只重新排序所需的元素,也可能最终成为大堆的许多操作。

如果效率太低,最小堆可能不合适。

二叉树可能更好(例如红黑树),其中删除和插入更好。

但是我不确定re-order in-place的rb-tree能力,因为min-heap可以做到。