6.1-1
元素最少的情况是最底层只有一个叶子,即$2^h$;元素最多的情况是整棵树是满的,即$2^{h+1}-1$。(这里按照叶子到根的最大边数来定义高度)
6.1-2
设高度为h,那么可知 $$2^h \le n \le 2^{h+1}-1$$ $$\Rightarrow h \le \lg n \lt h+1$$ $$\Rightarrow \lg n - 1 \lt h \le \lg n$$ 即$h = \lfloor \lg n \rfloor$。
6.1-3
令p(i)为第i个元素的父亲下标,那么对任意$i > 1$,都有$A[i] \le A[p(i)] \le A[p(p(i))] \le \cdots \le A[1]$,即都小于根元素。
6.1-4
最小的元素处于最底层或次底层的叶子结点,即该结点没有子结点。这时因为大根堆(max heap)中父结点一定不小于子结点,所以最小的元素必须出现在叶子结点上。
6.1-5
对于有序的数列肯定有$\forall i \lt j, a_i \lt a_j$,而$Parent(i) = i/2 \lt i$,故有$a_{Parent(i)} \lt a_i$,满足小根堆的性质。
6.1-6
树结构如下,元素7和6不满足大根堆的性质,故不是大根堆。
23 17 14 6 13 10 1 5 7 12
6.1-7
设堆的高度为h,那么除去最底层的结点的数量为$2^h = 2^{h+1}/2$个,所以底层结点的下标为$2^{h+1}/2 + 1, 2^{h+1}/2 + 2 \cdots ,n$,即$\lfloor n/2 \rfloor + 1, \lfloor n/2 \rfloor + 2, \cdots , n$
6.2-1
简单起见,我们只列出收影响的部分子树
3 10 1 8 9 0 --------- 10 3 1 8 9 0 --------- 10 9 1 8 3 0
6.2-2
只要把相应的最小元素移到父亲的位置即可
Min-Heapify(A, i)
l = Left(A, i)
r = Right(A, i)
if l <= A.heap-size and A[l] < A[i]
smallest = l
else
smallest = i
if r <= A.heap-size and A[r] < A[smallest]
smallest = r
if smallest != i
swap A[i] with A[smallest]
Min-Heapify(A, smallest)
由于只改变了比较部分,该算法的时间复杂度与Max-Heapify一致。
6.2-3
不会有任何改变。
6.2-4
当$i \gt A.heap-size/2$时,结点为叶子结点没有孩子,所以不会有任何改变。
6.2-5
Max-Heapify(A, i)
while true
l = Left(A, i)
r = Right(A, i)
if l <= A.heap-size and A[l] > A[i]
largest = l
else
largest = i
if r <= A.heap-size and A[r] > A[largest]
largest = r
if largest != i
swap A[i] with A[largest]
i = largest
else
break
6.2-6
Max-Heapify最坏的情况下对从根结点到最深的叶子结点中的所有结点都调用一遍自身,例如叶子结点大于到根结点路径上所有结点的值,如果结点数为n,那么高度为$\lg n$,如果每次比较和交换的时间为$\Theta (1)$,那么总时间为$\Theta (\lg n)$。
6.3-1
5 3 17 10 84 19 6 22 9 ------------------ 5 3 17 22 84 19 6 10 9 ------------------ 5 3 19 22 84 17 6 10 9 ------------------ 5 84 19 22 3 17 6 10 9 ------------------ 84 22 19 10 3 17 6 5 9
6.3-2
因为调用Max-Heapify都假定当前结点的左右子树都是堆,只有从下往上调用才能满足这样的前提。