[堆]- 删除节点后,您应该运行 筛选所有节点还是只筛选根节点?
[Heap]- after removing a node, should you run siftDown for all nodes or just the root?
我见过二叉堆的实现,其中在删除一个节点后,heapifyDown/siftDown(无论作者如何命名)仅在根上 运行 以重新堆化树,还有一些其中 siftDown 是 运行 从底部到根的所有项目的迭代。
我假设在删除节点之前,N 项的树已经 built/heapified 并且满足最小堆或最大堆 属性。如果那是真的 - 尝试 运行 筛选节点 (N//2)-1 [第一个从 0 开始索引的非叶节点] 及以上的节点有什么意义,更不用说从末尾开始的所有节点了 - 而不是只筛选根?这是一个糟糕的实现,还是我遗漏了什么?
*额外问题:从最小堆或最大堆的中间移除节点是否有任何原因?我认为提取根或者最后一个元素是最重要的。当堆用作数据结构时,是否在实践中做过?
移除最小值后,无需对所有元素进行 运行 heapifyDown / siftDown。这确实会修复堆,但这样做需要时间 O(n),这非常慢并且违背了拥有二叉堆的目的。相反,传统算法是将堆的最后一个元素交换到顶部,然后对其调用 heapifyDown / siftDown。这需要时间 O(log n),这比重建整个堆要快得多。
至于从堆中间移除节点——这相当罕见,但并非闻所未闻。更常见的是,对于像 Dijkstra 的最短路径算法或 Prim 的最小生成树算法这样的图算法,从堆中取出一个元素并降低其优先级(在最小堆中)或增加它(在最大堆中)。这可以通过在堆中定位元素,降低其优先级,然后对其调用 heapifyUp / siftUp 来恢复堆来完成 属性.
我见过二叉堆的实现,其中在删除一个节点后,heapifyDown/siftDown(无论作者如何命名)仅在根上 运行 以重新堆化树,还有一些其中 siftDown 是 运行 从底部到根的所有项目的迭代。
我假设在删除节点之前,N 项的树已经 built/heapified 并且满足最小堆或最大堆 属性。如果那是真的 - 尝试 运行 筛选节点 (N//2)-1 [第一个从 0 开始索引的非叶节点] 及以上的节点有什么意义,更不用说从末尾开始的所有节点了 - 而不是只筛选根?这是一个糟糕的实现,还是我遗漏了什么?
*额外问题:从最小堆或最大堆的中间移除节点是否有任何原因?我认为提取根或者最后一个元素是最重要的。当堆用作数据结构时,是否在实践中做过?
移除最小值后,无需对所有元素进行 运行 heapifyDown / siftDown。这确实会修复堆,但这样做需要时间 O(n),这非常慢并且违背了拥有二叉堆的目的。相反,传统算法是将堆的最后一个元素交换到顶部,然后对其调用 heapifyDown / siftDown。这需要时间 O(log n),这比重建整个堆要快得多。
至于从堆中间移除节点——这相当罕见,但并非闻所未闻。更常见的是,对于像 Dijkstra 的最短路径算法或 Prim 的最小生成树算法这样的图算法,从堆中取出一个元素并降低其优先级(在最小堆中)或增加它(在最大堆中)。这可以通过在堆中定位元素,降低其优先级,然后对其调用 heapifyUp / siftUp 来恢复堆来完成 属性.