已發布·持續改進
Algorithm
學習樹的術語與走訪、二元搜尋樹的搜尋、插入和刪除,以及二元堆積與優先佇列的原理、複雜度和實作程式碼。
樹是一種從根節點出發、依父子關係分支的階層式資料結構。為二元樹加上「小的鍵在左、大的鍵在右」的規則,就得到二元搜尋樹(BST);加上「父節點不大於子節點」的規則和完全二元樹的形狀,就得到二元堆積。本主題集中介紹樹的術語、四種走訪、二元搜尋樹、平衡樹、堆積與優先佇列。
樹和堆積是許多實際系統的骨架。資料庫索引使用 B 樹,C++ 的 std::map 和 Java 的 TreeMap 是紅黑樹,作業系統排程器、計時器以及 Dijkstra 最短路徑都仰賴樹或堆積。理解「高度決定效能」以及「堆積可以放在一個陣列裡」,就能判斷何時選用哪種結構,這些內容也是技術面試與程式檢定的常見考題。
建議先在紙上畫一棵小樹,親手走一遍前序、中序、後序與層序走訪。接著自己實作二元搜尋樹的插入、搜尋、刪除以及堆積的上浮與下沉,並弄清楚 heapify 為什麼是 O(n)。最後用 Python heapq、C++ priority_queue、Java PriorityQueue 等標準工具解決前 K 大、合併已排序串列等問題,鞏固所學觀念。
掌握根、葉、深度、高度等術語以及前序、中序、後序、層序走訪,就能讀懂並解決大多數樹的問題。
由於小的鍵在左、大的鍵在右,搜尋、插入和刪除的時間與樹高成正比,中序走訪可以得到排序後的序列。
輸入已排序時,二元搜尋樹會退化成鏈結串列。AVL 樹和紅黑樹透過旋轉把高度維持在 O(log n)。
把完全二元樹存進陣列,查看最小值為 O(1),插入和取出為 O(log n),對整個陣列建堆積為 O(n)。
用 Node 類別建構二元搜尋樹:bst_insert 透過比較鍵找到空位接上新節點,bst_search 用迴圈向下搜尋鍵。中序走訪的結果可以驗證鍵是依遞增順序排列。MinHeap 用串列保存元素,push 時上浮、pop 時下沉來維持堆積性質,因此取出的值由小到大排列。
trees_and_heaps.py
# Binary search tree (insert/search) and a binary min-heap
class Node:
def __init__(self, key):
self.key = key
self.left = None
self.right = None
def bst_insert(root, key):
if root is None:
return Node(key)
if key < root.key:
root.left = bst_insert(root.left, key)
elif key > root.key:
root.right = bst_insert(root.right, key)
return root # duplicates are ignored
def bst_search(root, key):
while root is not None and root.key != key:
root = root.left if key < root.key else root.right
return root is not None
def inorder(root, out):
if root is not None:
inorder(root.left, out)
out.append(root.key)
inorder(root.right, out)
return out
class MinHeap:
def __init__(self):
self.a = []
def push(self, x):
a = self.a
a.append(x)
i = len(a) - 1
while i > 0 and a[(i - 1) // 2] > a[i]: # sift up
p = (i - 1) // 2
a[i], a[p] = a[p], a[i]
i = p
def pop(self):
a = self.a
top, last = a[0], a.pop()
if a:
a[0] = last
i, n = 0, len(a)
while True: # sift down
small = i
for c in (2 * i + 1, 2 * i + 2):
if c < n and a[c] < a[small]:
small = c
if small == i:
break
a[i], a[small] = a[small], a[i]
i = small
return top
def __len__(self):
return len(self.a)
root = None
for k in [50, 30, 70, 20, 40, 60, 80]:
root = bst_insert(root, k)
print(inorder(root, [])) # [20, 30, 40, 50, 60, 70, 80]
print(bst_search(root, 60), bst_search(root, 65)) # True False
heap = MinHeap()
for x in [5, 3, 8, 1, 9, 2]:
heap.push(x)
print([heap.pop() for _ in range(len(heap))]) # [1, 2, 3, 5, 8, 9]
共六章,帶你從安裝一步步認識 樹與堆積 的核心概念。
在這裡提問、分享經驗,交流關於 樹與堆積 的看法。
還沒有討論。來發起第一則吧。
python trees_and_heaps.py
0 則留言
登入 · 登入後即可留言。
來留下第一則留言吧。