# BFS/DFS (本篇以樹為主) ## 觀念 >edges = [ [0, 1], [0, 2], [1, 3], [1, 4], [2, 5], [5, 6], [6, 7], [7, 2],# 形成一個循環 [4, 8], [8, 9] ] #### 快速將節點建立字典 ```python= from collections import defaultdict def build_graph(edges): graph = defaultdict(list) # 建立value為list的字典 for u, v in edges:# u=0,v=1 graph[u].append(v) graph[v].append(u) # 如果是無向圖 return graph ``` > 輸出:defaultdict(<class 'list'>, {0: [1, 2], 1: [0, 3, 4], 2: [0, 5, 7], 3: [1], 4: [1, 8], 5: [2, 6], 6: [5...略 #### BFS 廣度優先遍歷 ```python= from collections import deque # 雙向佇列 def bfs(graph, start):# graph為字典 visited = set() # 用集合避免無限循環 q = deque([start]) while q: node = q.popleft() if node in visited: continue visited.add(node) for neighbor in graph[node]:# 這個節點的鄰居 neighbor,都加入佇列 q,等待後續處理。 q.append(neighbor) return visited ``` # 建樹 給定一個層序遍歷的 list `P=[1,null,2]`(一個只有右節點的樹) ```python= from collections import deque # 定義二元樹節點類別 class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val # 根節點 self.left = left self.right = right ``` ## deque 建樹 ```python= # 從層序遍歷的 list 建立二元樹 def build_tree(li): if not li: return None root = TreeNode(li[0]) q = deque([root]) # 初始放入根節點 i = 1 while i < len(li): node = q.popleft() # 確認有東西後再建立節點 if i < len(li) and li[i] is not None: node.left = TreeNode(li[i]) q.append(node.left) i += 1 if i < len(li) and li[i] is not None: node.right = TreeNode(li[i]) q.append(node.right) i += 1 return root ``` ## index 建樹 很快,不過只適用於「中間沒 None」或你保證 list 是完整對應的層序結構 ```python= def build_tree_index(li): if not li: return None nodes = [TreeNode(val) if val is not None else None for val in li] for i in range(len(li)): if nodes[i]: l = 2 * i + 1 r = 2 * i + 2 if l < len(li): nodes[i].left = nodes[l] if r < len(li): nodes[i].right = nodes[r] return nodes[0] ``` 這時候`print(build_tree(p))` 會是`<__main__.TreeNode object at 0x0000014D6B029390>` :::spoiler 要讓他變可視化要下面這段程式碼 ```python= def print_tree(root): if not root: return q = deque([root]) while any(q): node = q.popleft() print(node.val if node else 'None', end=' ') if node: q.append(node.left) q.append(node.right) print(print_tree(build_tree(p))) ``` ::: # BFS 呈上,用剛剛建的樹來跑一次BFS! ```python= def bfs(start): queue = [start] result = [] while queue: curr = queue.pop(0) result.append(curr.val) if curr.left: queue.append(curr.left) if curr.right: queue.append(curr.right) return result #測試 result = bfs(build_tree(p)) print(result) ``` # DFS 深度優先 ```python= def dfs(node): if not node: return [] result = [node.val] # 先處理當前節點(Pre-order) result += dfs(node.left) # 再處理左子樹 result += dfs(node.right) # 最後處理右子樹 return result #測試 result = dfs(build_tree(q)) print("dfs",result) ``` # 無向迷宮圖 1. 判斷要用dfs/bfs遍歷 2. 建立上下左右`[(-1,0),(1,0),(0,-1),(0,1)]` (i-1 = 往上一列) 3. 建立visited[] :::spoiler 如果對角線也能走 directions = [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)] ::: ## 遍歷模板 ```python= for dx, dy in [(-1, 0), (1, 0), (0, -1), (0, 1)]: nx = x + dx ny = y + dy # 接著你可以檢查 (nx, ny) 是否有效或是牆壁等 ``` 練習:https://hyc.eshachem.com/counting-rooms/