使用最小/最大堆算法时,优先级可能会发生变化。处理此问题的一种方法是删除并插入元素以更新队列顺序。
对于使用数组实现的优先级队列,这可能是一个似乎可以避免的性能瓶颈,尤其是在优先级变化很小的情况下。
Even if this is not a standard operation for a priority queue,这是一个自定义实现,可以根据我的需要进行修改。
是否有众所周知的最佳实践方法来更新min / max-heap中的元素?
背景信息:我不是二叉树专家,我继承了一些在优先级队列中重新插入元素的性能瓶颈的代码。我为重新排序新元素的min-heap做了一个重新插入函数 - 这给了一个可测量的改进(删除和插入),但这似乎是其他人可能已经解决的问题优雅的方式。
我可以链接到代码,如果它有帮助,但宁愿不太关注实现细节 - 因为这个Q& A可能保持一般。
答案 0 :(得分:17)
通常的解决方案是将元素标记为无效并插入新元素,然后在弹出时删除无效条目。
如果该方法不够,只要知道要更改的值的位置,就可以在O(log n)步骤中恢复min-heap不变量。
回想一下,使用两个原语“siftup”和“siftdown”来构建和维护min-heap(尽管各种来源对于哪个来源有不同的意见,哪些是关闭的)。其中一个将值推到树下,另一个将它们向上浮动。
如果新值 x1 大于旧值 x0 ,则只需要修复 x 下的树,因为{{ 1}}。只需按 x 将 x 与其两个子项中较小的一个交换为 x ,而 x 大于其中一个子< /强>
如果新值 x1 小于旧值 x , x 下面的树不需要调整,因为parent(x) <= x0 < x1
。相反,我们只需向上移动,将 x 与其父级进行交换,而 x 小于其父级。不需要考虑兄弟节点,因为它们已经大于或等于可能被较低值替换的父节点。
无需工作。现有的不变量没有变化。
测试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);
}
虽然操作次数取决于值的分布,但这将等于或少于维护排序列表的步骤。
通常,较小的更改比删除+插入更有效。
查看工作code和test,它实现了带有insert / remove / re-prioritize的最小堆,没有初始查找(调用者存储不透明引用)。
即使只重新排序所需的元素,也可能最终成为大堆的许多操作。
如果效率太低,最小堆可能不合适。
二叉树可能更好(例如红黑树),其中删除和插入更好。
但是我不确定re-order in-place的rb-tree能力,因为min-heap可以做到。