5.1 二元樹的走訪#
概念說明#
走訪(traversal)是「把樹上每個節點拜訪一次」的套路,是一切樹演算法的地基。二元樹有四種經典順序:
- 前序(preorder):根 → 左子樹 → 右子樹。適合「複製樹、序列化」。
- 中序(inorder):左子樹 → 根 → 右子樹。對 BST 而言輸出由小到大的排序結果。
- 後序(postorder):左子樹 → 右子樹 → 根。適合「先算子樹再合併」,如目錄大小統計、釋放樹。
- 層序(level-order):一層一層由左至右,用佇列實作,屬於廣度優先。
前三者是深度優先(DFS),差別只在「根」被拜訪的相對位置;層序用佇列,前三者用遞迴或堆疊。
Python 實作#
class TreeNode:
def __init__(self, val):
self.val = val
self.left = None
self.right = None
def preorder(node, out):
if node:
out.append(node.val)
preorder(node.left, out)
preorder(node.right, out)
def inorder(node, out):
if node:
inorder(node.left, out)
out.append(node.val)
inorder(node.right, out)
def postorder(node, out):
if node:
postorder(node.left, out)
postorder(node.right, out)
out.append(node.val)
def level_order(root):
from collections import deque
out, q = [], deque([root] if root else [])
while q:
node = q.popleft()
out.append(node.val)
if node.left: q.append(node.left)
if node.right: q.append(node.right)
return out
# 建一棵樹: 1
# / \
# 2 3
# / \ \
# 4 5 6
root = TreeNode(1)
root.left, root.right = TreeNode(2), TreeNode(3)
root.left.left, root.left.right = TreeNode(4), TreeNode(5)
root.right.right = TreeNode(6)
for name, fn in [("前序", preorder), ("中序", inorder), ("後序", postorder)]:
out = []
fn(root, out)
print(f"{name}: {out}")
print(f"層序: {level_order(root)}")
# 前序: [1, 2, 4, 5, 3, 6]
# 中序: [4, 2, 5, 1, 3, 6]
# 後序: [4, 5, 2, 6, 3, 1]
# 層序: [1, 2, 3, 4, 5, 6]
迭代版(用堆疊)與實用衍生#
遞迴本質上靠呼叫堆疊;改用顯式堆疊可寫成迭代版,也能順手寫出「樹高」等實用函式:
def preorder_iter(root):
out, stack = [], [root] if root else []
while stack:
node = stack.pop()
out.append(node.val)
if node.right: stack.append(node.right) # 先壓右,讓左先出
if node.left: stack.append(node.left)
return out
def height(node):
if node is None:
return 0
return 1 + max(height(node.left), height(node.right))
def count_nodes(node):
if node is None:
return 0
return 1 + count_nodes(node.left) + count_nodes(node.right)
print(preorder_iter(root)) # [1, 2, 4, 5, 3, 6]
print(height(root), count_nodes(root)) # 3 6
複雜度分析#
四種走訪都拜訪每個節點恰一次,時間 O(n)。空間:遞迴/堆疊版為 O(h)(h 為樹高,最壞鏈狀 O(n)、平衡 O(log n));層序的佇列最壞 O(n)(最寬一層)。
練習#
- 實作中序的迭代版(用堆疊一路壓左子孫、pop 拜訪、再轉向右子樹)。
- 兩棵樹的「中序 + 前序」可唯一重建樹,但「中序 + 後序」也可以,「前序 + 後序」不行。請用 n=2 的例子說明原因。
- 實作
zigzag_level_order:層序但奇數層反向輸出(第一層左→右、第二層右→左…)。