在阅读了诸如Why siftDown is better than siftUp in heapify?之类的问题之后,我得到了这样的印象
sifdown()比siftUp()好
siftdown()总是可以替换siftup(),反之亦然
为什么很多堆结构实现都有siftup()在insert()上调用?维基百科上有。

最佳答案

筛选元素的BuildHeap方法是使用现有数组最快已知的方法,并将其转换为堆。它比一次插入一个条目要快,比从底部向上筛选元素要快。
但是,一旦构建了堆,并且在数据结构上执行了一系列插入和删除操作,在底部插入项并将其向上筛选比在顶部插入并向下筛选要快得多。
记住,在n个项的堆中,n/2个项处于叶级。这意味着当你插入一个项目(通过将其作为下一页添加)时,有50%的可能性它不必筛选:它已经在正确的位置了。有25%的可能性它属于下一个级别。当您在堆中向上移动时,项目筛选到该级别的概率降低50%。
现在,您可以编写堆代码来一直在顶部执行插入,但是概率对您不利。仍然有50%的可能性,你插入的项目将结束在叶级。除非你把它插在最上面,它会把你的日志交换到那里。
因此,如果你在底部插入并向上筛选:

50% of the time you make 0 swaps
25% of the time you make 1 swap
12.5% of the time you make 2 swaps
...

如果在顶部插入并向下筛选:
50% of the time you make log(n) swaps
25% of the time you make log(n)-1 swaps
12.5% of the time you make log(n)-2 swaps
...

想想看,比这还糟。因为如果你要插入一个项目,它最终降落在中间的某个地方,你就必须把它替换掉的项目筛选下来最后会把东西从堆里搬下来。最后,在顶部插入总是要花费您记录(n)交换的成本,因为您最终必须在数组中的(n+1)位置放置一些东西(即,您必须添加一个项)。
应该清楚的是,您不想在顶部插入,尽管在移除根时必须执行类似的操作。
移除根目录时,将堆中的最后一项放入根目录位置,并将其向下筛选考虑到你是从叶级得到的,并且考虑到叶级包含了一半的项目,很有可能(略好于50%)它会回到叶级请注意,这并不总是会导致日志(n)交换,因为您没有插入项;您只是在调整堆。
这就是为什么,顺便说一句,在编写良好的二进制堆实现中,删除根元素比插入一个新项要昂贵。

10-07 19:34