笔记
本节主要考虑如何保持堆(最大堆)的性质。给定最大堆
中的一个元素
,它有可能不符合最大堆的性质,即
有可能小于它的孩子,但是它的两棵子树已经满足了最大堆的性质。我们通过一个MAX-HEAPIFY过程来使得以
为根的子树满足最大堆性质,MAX-HEAPIFY是通过让
在最大堆中“逐层下降”来达成这一目标的。
简单描述一下MAX-HEAPIFY的执行过程。先从
中找出最大值,并将最大值的下标保存在
中。如果
是最大的,那么以
为根的子树已经满足最大堆性质,无需再做调整。如果
不是最大的,那么最大值必然是
的某个孩子,交换
和
,将
放置到子树的根的位置,使得
这三个结点满足最大堆性质。然而,由于
被放置到了
位置,那么现在的
也有可能小于它的孩子,因此还需要对以
为根的子树递归调用MAX-HEAPIFY。可以看到,如果
不满足最大堆性质,那么
就会逐层下降,直到满足最大堆性质为止,或者直到降到最底层为止。
下图给出了一个例子。初始时
,然后逐层下降,一直降到了最底层。
MAX-HEAPIFY的核心是让不满足最大堆性质元素逐层下降,而逐层下降的次数不会超过整棵树的高度,因此MAX-HEAPIFY的时间复杂度为
,也就是
。
练习
6.2-1 参照图6-2的方法,说明MAX-HEAPIFY(A, 3)在数组A = <27, 17, 3, 16, 13, 10, 1, 5, 7, 12, 4, 8, 9, 0>上的操作过程。
解
6.2-2 参考过程MAX-HEAPIFY,写出能够维护最小堆的MIN-HEAPIFY(A, i)伪代码,并比较MIN-HEAPIFY与MAX-HEAPIFY的运行时间。
解
显然,MIN-HEAPIFY与MAX-HEAPIFY的运行时间一样,也为
。
6.2-3 当元素
比其孩子的值都大时,调用MAX-HEAPIFY(A, i)会有什么结果?
解
元素
比其孩子的值都大时,
满足最大堆的性质,调用MAX-HEAPIFY(A, i)不会有任何改变。
6.2-4 当
时,调用MAX-HEAPIFY(A, i)会有什么结果?
解
根据练习6.1-7的结论,当
时,
一定为叶结点,故调用MAX-HEAPIFY(A, i)不会有任何改变。
6.2-5 MAX-HEAPIFY的代码效率较高,但第10行中的递归调用可能例外,它可能使某些编译器产生低效的代码。请用循环控制结构取代递归,重写MAX-HEAPIFY代码。
解
6.2-6 证明:对一个大小为
的堆,MAX-HEAPIFY的最坏情况运行时间为
。(提示:对于
个结点的堆,可以通过对每个结点设定恰当的值,使得从根结点到叶结点路径上的每个结点都会递归调用MAX-HEAPIFY。)
解
利用练习6.1-2的结论,含有
个元素的堆高度为
。MAX-HEAPIFY的最坏情况为,从树的根结点开始,逐层下降,直到最底层。因此MAX-HEAPIFY的最坏情况运行时间为
。