我试图证明对于二进制堆,buildHeap最多(2N-2)在元素之间进行比较。 我发现很难证明这一说法。
答案 0 :(得分:7)
构建堆算法从中点开始,并根据需要向下移动项目。让我们考虑一堆127项(7个级别)。在最坏的情况下:
64 nodes (the leaf level) don't move at all
32 nodes move down one level
16 nodes move down two levels
8 nodes move down three levels
4 nodes move down four levels
2 nodes move down five levels
1 node moves down six levels
所以在最坏的情况下你有
64*0 + 32*1 + 16*2 + 8*3 + 4*4 + 2*5 + 1*6
0 + 32 + 32 + 24 + 16 + 10 + 6 = 120 swaps
因此,在最坏的情况下,构建堆的交换次数少于N次。
因为构建堆要求您将项目与其子项的最小项交换,所以需要进行两次比较来启动交换:一项用于查找两个子项中的最小项,另一项用于确定节点是否更大且必须被交换。
移动节点所需的比较次数为2*(levels_moved+1)
,并且移动的节点数不会超过N / 2个。
我们需要证明最大比较次数不超过2N-2。如上所述,将节点移动一级需要两次比较。因此,如果移动的级别数小于N(即(N-1)或更少),则最大比较次数不能超过2N-2。
我在下面的讨论中使用了完整的堆,因为它代表了最糟糕的情况。
在N个项目的完整堆中,叶级别有(N + 1)/ 2个节点。 (N + 1)/ 4在下一级别上升。 (N + 1)/ 8,等等。你最终得到这个:
(N+1)/2 nodes move 0 levels
(N+1)/4 nodes move 1 level
(N+1)/8 nodes move 2 levels
(N+1)/16 nodes move 3 levels
(N+1)/32 nodes move 4 levels
...
这给了我们系列:
((N+1)/2)*0 + ((N+1)/4)*1 + ((N+1)/8)*2 + ((N+1)/16)*3 ...
让我们看看它对大小不同的大小有什么影响:
heap size levels levels moved
1 1 0
3 2 1
7 3 2*1 + 1*2 = 4
15 4 4*1 + 2*2 + 1*3 = 11
31 5 8*1 + 4*2 + 2*3 + 1*4 = 26
63 6 16*1 + 8*2 + 4*3 + 2*4 + 1*5 = 57
127 7 32*1 + 16*2 + 8*3 + 4*4 + 2*5 + 1*6 = 120
....
我运行了最多20个级别(大小一百万并且更改),并且它仍然成立:N个项目的完整堆移动的最大级别数是N-log2(N + 1)。
将上述系列视为Arithetico-geometric Sequence,我们计算log2(N + 1) - 1
项的总和,忽略第一项为零,等于N - 1
。 (回想一下完整的二叉树有log2(N + 1)
级别)
此总和表示执行筛选操作的总次数。因此所需的比较总数为2N - 2
(因为每次筛选操作需要两次比较)。这也是上限,因为完整的二叉树总是代表给定树深度的最坏情况。