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 的堆,其高度與最大結點數的關係仍是上式。