6.1-1算法
在高度为 h 的堆中,元素最多有 2h+1 - 1 个,最少有 2h 个。注意算法导论里的高度是指深度,从 0 开始而不是从 1 开始。数组
6.1-2spa
这很好想,可是很差证实。code
由已知高度为 h 的堆,它的元素个数知足 2h <= n <= 2h+1 - 1 ,解出 lg(n+1) - 1 <= h <= lgn ,可是它不够“合理”,由于当 n = 2h+1-1 时,n 等于 2的幂 - 1,此时 lg(n+1) -1 = ⌊lgn⌋ ,因此 ⌊lgn⌋ <= h <= lgn 。而咱们默认高度 h 是一个天然数,因此左右界一致,得出 h = ⌊lgn⌋ 。blog
6.1-3排序
最大堆的属性告诉咱们除了根结点之外的全部结点都要知足 A[PARENT(I)] >= A[I] ,一棵树是递归定义的,因此子树的最大结点确定是其根结点。递归
6.1-4索引
它必定是叶子结点,位于 ⌊lgn⌋ 或 ⌊lgn⌋ - 1 层class
6.1-5循环
按递增排序的话,是的
6.1-6
不是,"PARENT" 6 < "CHILD" 7
6.1-7
经过反证法比较好证实。
假设 i ∈ { ⌊n/2⌋+1, ⌊n/2⌋+2, ... , n } ,那么它的孩子的序号至少是 2·(⌊n/2⌋+1), 2·(⌊n/2⌋+2) ,显然不在数组内。
因此能够获得结论:堆中叶子结点数 = ⌈n+1⌉
6.2-1
3 先与左右儿子比较,找到其中最大的关键字并记录它的索引,让它与 3 交换,递归调用实现 3 的子树堆化。
6.2-2
维护最小堆的算法以下:
#define LEFT(i) (2*i + 1) #define RIGHT(i) (2*i + 2) MIN-HEAPIFY (A, i) left = LEFT (i) right = RIGHT (i) if left <= A.HEAPSIZE && A[left] < A[i] min_index = left else min_index = i if right <= A.HEAPSIZE && A[right] < A[min_index] min_index = right if min_index != i exchange A[i] and A[min_index] MIN-HEAPIFY(A, min_index)
时间同样,都是 Θ(lgn)
6.2-3
不会进行递归堆化。
6.2-4
其子结点的序号超出了堆的大小,程序将视为其子结点不存在,因此不会进行堆化操做。
6.2-5
尾递归改循环控制结构以下:
#define LEFT(i) (2*i + 1) #define RIGHT(i) (2*i + 2) MAX-HEAPIFY (A, i) while i < A.HEAPSIZE left = LEFT(i) right = RIGHT(i) if left < A.HEAPSIZE && A[left] > A[i] max_index = left else max_index = i if right < A.HEAPSIZE && A[right] > A[max_index] max_index = right if max_index != i exchange A[max_index] and A[i] else return;
6.2-6
...
6.3-1
从 ⌊A.length/2⌋ 开始,即第一个非叶子结点 10 开始(最大)堆化,而后是 三、二、1 。过程很简单,直接写结果了,获得的数组是 {84, 22, 19, 10, 3, 17, 6, 5, 9}
6.3-2
咱们从 ⌊n/2⌋ 开始的目的是要让每次迭代先后 i 都是最大堆的根。若是从 1 开始,那么将没法保持最大堆的特性(没法保证循环不变式)。
6.3-3
这里将利用到 6.1-7 的结论:堆中叶子结点数 = ⌈n/2⌉
首先,当 h = 0 时(算法导论中高度深度都是从 0 开始),高度为零的堆就是叶子结点组成的堆,有 ⌈n/2⌉ 个这样的堆,结点数是 ⌈n/2⌉
假设当 h = h-1 时,结论成立。
有一颗高度为 h 的堆,若是把它的叶子结点都剪去后它将变成高度为 h - 1 、结点数为 n - ⌈n/2⌉ = ⌊n/2⌋ 的堆,代入 h = h-1 时的结论,有以下推导:
同理,咱们能够用高度为 h+1 的堆剪去叶子结点获得高度为 h 的堆,其高度与最大结点数的关系仍是上式。