堆排序算法
n=m
for k:= m div 2 down to 0
downheap(k);
repeat
t:=a[0]
a[0]:=a[n-1]
a[n-1]:=t
n—
downheap(0);
until n <= 0
有人可以向我解释在行中做了什么
n=m
for k:= m div 2 down to 0
downheap(k);
我认为这是堆构建过程,但for k:= m div 2 down to 0
也是n项的数量。在数组表示中,最后一个元素存储在[n-1]? 但是为什么n> = 0.我们不能在n> 0完成。因为第一个元素会自动排序吗?
答案 0 :(得分:2)
n=m
for k:= m div 2 down to 0
downheap(k);
在二进制堆中,有一半节点没有子节点。因此,您可以通过从中点开始并向下筛选项目来构建堆。你在这里做的是从下往上构建堆。考虑这五个项目的数组:
[5, 3, 2, 4, 1]
或者,作为一棵树:
5
3 2
4 1
长度为5,所以我们想从索引2开始(假设一个基于1的堆数组)。然后,downheap
将查看标记为3
的节点,并将其与最小的子节点进行比较。由于1小于3,我们交换项目给出:
5
1 2
4 3
由于我们达到了叶级,我们已完成该项目。转到第一个项目5
。它小于1
,所以我们交换项目:
1
5 2
4 3
但是项目5
仍然比其子项大,所以我们进行另一次交换:
1
3 2
4 5
我们已经完成了。你有一个有效的堆。
用手工(用铅笔和纸)来构建一个更大的堆 - 比如10个项目是有益的。这将使您非常了解算法的工作原理。
为了以这种方式构建堆,如果数组索引从0或1开始并不重要。如果数组从0开始,那么你最后再调用downheap
,但这没有做任何事情,因为您尝试向下移动的节点已经是叶子节点。所以它效率稍低(对downheap
的一次额外调用),但没有害处。
但重要的是,如果您的根节点位于索引1处,则使用n > 0
而非n >= 0
停止循环。在后一种情况下,您最终可能会在堆中添加虚假值并删除应该存在的项。
答案 1 :(得分:0)
for k:= m div 2 down to 0
这似乎是伪代码:
for(int k = m/2; k >= 0; k--)
或者可能
for(int k = m/2; k > 0; k--)
取决于&#34;降至0&#34;包容与否。
也是n项数?
最初,是的,但它会在n-
行上减少。
我们不能在n> 0完成。因为第一个元素会自动排序吗?
是的,这实际上就是这样。一旦N在n-
变为零,它就会在循环体的大部分时间内完成,因此在此之后until n <= 0
终止之前执行的唯一事情是downheap(0);