堆
堆:是一個陣列,近似的完全二叉樹,除了最底層外,該樹是完全充滿的.
最小堆:A[i] <= A[2i] && A[i] <= A[2i+1]
最大堆:A[i] >= A[2i] && A[i] >= A[2i+1]
下標從1開始算起
維護堆
max_heapify(A, i):維護最大堆的性質,讓A[i]的值逐級下降
if 2*i <= len(A) and A[2*i] > A[i]:
largest = 2*i
else:
largest = i
if 2*i+1 <= len(A) and A[2*i+1] > A[i]:
largest = 2*i+1
else:
largest = i
if largest != i:
A[i],A[largest] = A[largest],A[i]
max_heapify(A,largest)
時間複雜度:(見演算法導論第三版6.2節)
對於一個以i為根節點、大小為n的子樹,交換值的代價為O(1),加上,以i的一個孩子為根節點的子樹執行max_heapify的時間,每個孩子的子樹的大小至多為2n/3(最壞情況發生在樹的最底層恰好半滿的時候)
這兒的2n/3的推導:
1、假設有一個包含n個元素的堆, 計算高度為 h=k 的節點數的上限
2、假設有一個完全二叉樹,其中底層正好半滿,即有x個節點。我們可以透過新增x個節點來構造一個滿二叉樹
3、滿二叉樹的大小為 n + x = 2x * 2 - 1 = 4x - 1 。因此,我們有 n = 3x - 1,進而 x = (n + 1) / 3。
4、在滿二叉樹中,第i層的節點數目為 (滿樹大小 - 1) / 2。代入上述結果,我們得到 2x - 1 = 2n/3 - 1/3 < 2n / 3。
因此,在一個最大堆中,節點i的子樹大小至多為2n/3
由此,
T(n) ≤ T(2n/3) + O(1) ----> T(n)=O(lg n)
即對於一個樹高為h的節點,該操作的時間複雜度是O(h)。
建堆
最大堆:自底向上
build-max-heap(A):從最後一個非葉子節點開始,逐級向上維護最大堆的性質
A.heap-size = len(A)
for i in range(len(A)//2,0,-1):
max_heapify(A,i)
時間複雜度
初看是O(n lgn),精確是:O(n)
1、高為h的 至多節點個數
2、線性時間構造最大堆
這兒推導不是很明白!!!再看!!!
堆排序
heapsort(A):
build-max-heap(A)
for i in range(len(A),1,-1):
A[1],A[i] = A[i],A[1]
A.heap-size = A.heap-size - 1
max_heapify(A,1)