Heap 堆積
- 構造為 tree
- 每一個親節點對任何一個子節點都保持著某一特定關係
例:parent </≤/>/≥ children - 所有的子樹的親子節點也都是相同特定關係的 heap
※ 通常說 heap 指的即是 binary heap
Binary Heap
- 符合所有 heap 的條件
- 為一 complete binary tree
[Python] 使用 heapq 實作 binary heap / priority queue
Python 中的 Heap 定義
- 為一 list
all(heap_x[k] <= heap_x[2*k+1] and heap_x[k] <= heap_x[2*k+2] for all k in range(len(heap_x)))
為True
heap_x[0]
≡min(heap_x)
(如果 len(heap_x) > 0)
- 和 binary tree 的映射
- heap_x[0] 為 binary tree 的 root (第 0 層)
- 令 k = (2 ** p – 1) + r, 0 <= r < 2 ** p – 1
⇒ heap_x[k] 相當於 binary tree 中第 p 層的第 r 個 node (0-indexed)
Methods
Syntax | Description | Average Time Complexity | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
在線性時間內將 list_x 轉為 heap, heapq 預設的 key 是: |
O(len(list_x)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
\begin{align} |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
heapq.heappush( heap_x, item_a ) |
把 item_a 放進 heap_x, 並保持 heap_x 的 heap 性質不變 |
O(log(len(heap_x))) ≡ O(height of heap_x) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
![]() ![]() |
|
O(log(len(heap_x))) ≡ O(height of heap_x) |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
heapq.heappushpop( heap_x, item_a ) |
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
heapq._siftdown( heap_x, startpos, pos ) |
使 heap_x[pos] 一路往上
|
O(len(heap_x)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
heapq._siftup(heap_x, pos) |
|
O(len(heap_x)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
heap_x[i] = heap_x[-1]qwa # 把 heap_x[-1] 的值保留在 heap_x[i] heap_x.pop() # 再用 list 的 pop() 移除 heap_x[-1] heapq.heapify(heap_x) # 重新將 heap_x 給 heap 化 |
Delete element from heap | O(len(heap_x)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
heap_x[i] = heap_x[-1] |
O(log(len(heap_x))) |
heapq._siftdown(heap, startpos, pos) 和 heapq._siftup(heap, pos) 的 Source Code
# 'heap' is a heap at all indices >= startpos, except possibly for pos. pos # is the index of a leaf with a possibly out-of-order value. Restore the # heap invariant. def _siftdown(heap, startpos, pos): newitem = heap[pos] # Follow the path to the root, moving parents down until finding a place # newitem fits. while pos > startpos: parentpos = (pos - 1) >> 1 parent = heap[parentpos] if newitem < parent: heap[pos] = parent pos = parentpos continue break heap[pos] = newitem # The child indices of heap index pos are already heaps, and we want to make # a heap at index pos too. We do this by bubbling the smaller child of # pos up (and so on with that child's children, etc) until hitting a leaf, # then using _siftdown to move the oddball originally at index pos into place. # # We *could* break out of the loop as soon as we find a pos where newitem <= # both its children, but turns out that's not a good idea, and despite that # many books write the algorithm that way. During a heap pop, the last array # element is sifted in, and that tends to be large, so that comparing it # against values starting from the root usually doesn't pay (= usually doesn't # get us out of the loop early). See Knuth, Volume 3, where this is # explained and quantified in an exercise. # # Cutting the # of comparisons is important, since these routines have no # way to extract "the priority" from an array element, so that intelligence # is likely to be hiding in custom comparison methods, or in array elements # storing (priority, record) tuples. Comparisons are thus potentially # expensive. # # On random arrays of length 1000, making this change cut the number of # comparisons made by heapify() a little, and those made by exhaustive # heappop() a lot, in accord with theory. Here are typical results from 3 # runs (3 just to demonstrate how small the variance is): # # Compares needed by heapify Compares needed by 1000 heappops # -------------------------- -------------------------------- # 1837 cut to 1663 14996 cut to 8680 # 1855 cut to 1659 14966 cut to 8678 # 1847 cut to 1660 15024 cut to 8703 # # Building the heap by using heappush() 1000 times instead required # 2198, 2148, and 2219 compares: heapify() is more efficient, when # you can use it. # # The total compares needed by list.sort() on the same lists were 8627, # 8627, and 8632 (this should be compared to the sum of heapify() and # heappop() compares): list.sort() is (unsurprisingly!) more efficient # for sorting. def _siftup(heap, pos): endpos = len(heap) startpos = pos newitem = heap[pos] # Bubble up the smaller child until hitting a leaf. childpos = 2*pos + 1 # leftmost child position while childpos < endpos: # Set childpos to index of smaller child. rightpos = childpos + 1 if rightpos < endpos and not heap[childpos] < heap[rightpos]: childpos = rightpos # Move the smaller child up. heap[pos] = heap[childpos] pos = childpos childpos = 2*pos + 1 # The leaf at pos is empty now. Put newitem there, and bubble it up # to its final resting place (by sifting its parents down). heap[pos] = newitem _siftdown(heap, startpos, pos)
Ref
Last Updated on 2024/12/14 by A1go