原本想先從Fibonacci heap著手,突然想到heap本身其實也很值得紀錄一番,遂由此而起。
Heap : 中文又稱"堆積",常見的為二元堆積(Binary Heap),是一由大到小 or 由小到大的二元樹結構。
Mergeable : 任何data structures可以支援以下5種操作,且所有elements都有key;
- MAKE-HEAP ()
- INSERT (H , x)
- MINIMUM (H)
- EXTRACT-MIN (H)
- UNION (H1 , H2)
Heap property : H[ Parent(i) ] ≤ or ≥ H[ i ] , ∀ i ∈ Index
Note : 由於應對之後使用多是為minimum form,所以以下思路以此為主;log底數皆為2。
- Heapify的精神 : 把一node所有children與其相比,如果較大/小就把index存起來,遍歷完成後檢查index是否跟parent相符,不符就互換,並遞迴執行Heapify(H , index)。
HEAPIFY (H , i)
smallest = l
smallest = r if smallest ≠ i exchange H[ i ] with H[ smallest ] HEAPIFY (H , smallest) |
Recurrence : T (n) ≤ T (2n/3) + Θ (1)
Time complexity : O (log n)
|
- Build-Heap的精神 : 利用上述的Heapify,給定heap-size來建構一個heap。
BUILD-MIN-HEAP (H) H.heap-size = H.length for i = H.length/2 downto 1 HEAPIFY (H , i) |
Recurrence : T (n) ≤ 2T (n/2) + log n
Time complexity : O (n)
|
- HeapSort 的精神 : 把最後一個element與root交換,提出最後一個element後再對root做Heapify,重複到最後可得出由大到小的排列。
HEAPSORT (H) BUILD-MIN-HEAP (H) for i = H.length downto 2 exchange H[ 1 ] with H[ i ] H.heap-size -- HEAPIFY (H , 1) |
Time complexity : O (nlog n) Build-Heap使用了O (n),for迴圈使用了n-1次,而Heapify為 log n,其餘為constant time,故為 O (n) + (n - 1)*(log n +C) = O (nlog n) |
Priority queues : 一種data structure處理 set,作為heap的一種延伸應用,可以處理INSERT、MINIMUM、EXTRACT-MIN、INCREASE-KEY等operations。
Note : priority queue應用層面相當廣泛,課本中舉例為event-driven simulator,使用Extract Min 來選擇優先發生的事件作處理,Insert把新事件插入priority queue中;或是scheduler、pipeline manager之類需要取前後順序的系統都能使用上,而且在插入、刪除node的速度不慢,也適合套用在各類演算法中。
- Minimum/Maximum的精神 : 由於heap已經定義好max/min了,直接取root即可。
HEAP-MINIMUM return H[ 1 ] |
Time complexity : Θ (1) Trivial. |
- Extract Min的精神 : 使用HeapSort中把root與最後一個element調換並提出的技巧,把min提出,亦即是,做一次的HeapSort。
HEAP-EXTRACT-MIN (H) if H.heap-size < 1 error "heap underflow"min = H[ 1 ] H[ 1 ] = H[ H.heap-size ] H.heap-size -- HEAPIFY (H , 1) return min |
Time complexity : O (log n) Trivial. |
- Increase Key的精神 : 由於改變element's key可能會導致不符合heap結構邏輯,然而真正影響的只有ancestors,sibling or offspring不會受影響,所以只要trace back parents即可。
HEAP-INCREASE-KEY (H , i , key) if key < H[ i ] H[ i ] = key exchange H[ i ] with H[ Parent (i) ] |
Time complexity : O (log n)從current node trace back to root總共路徑長為樹高,則h = log n。 note : 不會為O (n)的原因為heap是一種 binary complete tree。 |
- Heap Insert的精神 : 先設一個key = −∞ 的element,並加在heap末端,再對其做Increase Key。
- 由於Increase Key已經處理結構邏輯問題,故不需要Heapify
HEAP-INSERT(H , Key) H.heap-size ++ |
Time complexity : ⇔ Increase Key = O (log n) |
末碎碎念:
沒想到心血來潮寫個heap花一堆時間,打文章要注意排版真是麻煩,而且巴哈排版又特別難用,應該使用hackmd 或 medium再貼上才對哈哈,不過算啦,這篇也算是搞懂了怎麼使用,之後應該會上手很多。
Ref :
- T. Cormen, C. E. Leiserson, R. L. Rivest, and C. Stein, Introduction to Algorithms, third edition, the MIT press, 2009
- B. F. Wang, 上課講義