--- tags: 演算法, LeetCode disqus: HackMD --- # 廣度優先搜尋BFS ## 介紹 :::info 節點選項是用 **先進先出(FIFO)** 方式進行管理,所以可以使用佇列的資料結構 ::: ![](https://i.imgur.com/2hF1XKW.gif) 廣度優先搜尋(BFS)是一種圖形搜尋演算法,從圖的起點開始搜尋,先遍歷所有距離起點為`1`的節點,再遍歷所有距離起點為`2`的節點,以此類推直到所有可達節點都被遍歷。 `BFS`適用於需要找到最短路徑或最少步驟的問題,例如迷宮遊戲或圖形路徑問題 ## 虛擬碼 以下是使用 `JavaScript` 撰寫的 `BFS` 演算法的簡易虛擬碼範本: ```javascript= // 假設圖形表示為鄰接表 adjacency list 的形式 // graph: 圖形,start: 起點,end: 終點 function BFS(graph, start, end) { // 用來保存已訪問的節點 const visited = new Set(); // 用來保存尚未探索的節點 const queue = []; // 將起點加入佇列 queue.push(start); // 標記起點已訪問 visited.add(start); while (queue.length > 0) { // 取出佇列中的下一個節點 const node = queue.shift(); // 如果找到終點,返回路徑 if (node === end) { return true; // 找到終點 } // 對節點的所有鄰接節點進行訪問 for (const neighbor of graph[node]) { // 如果鄰接節點未被訪問,加入佇列 if (!visited.has(neighbor)) { queue.push(neighbor); // 標記鄰接節點已訪問 visited.add(neighbor); } } } return false; // 無法到達終點 } graph = { 1: [2, 3], 2: [1, 4], 3: [1, 4], 4: [2, 3, 5], 5: [4] }; console.log(BFS(graph, 1, 5)); ``` 這個 `BFS` 實現使用 `Set` 來保存已訪問的節點,使用佇列來保存尚未探索的節點,並在佇列中使用先進先出的方式來探索圖形。 ## 複雜度 ### 時間複雜度 $O(V+E)$ 其中 `V` 是節點的數量,`E` 是邊的數量。在最壞的情況下,`BFS` 將遍歷圖形中的每個節點和每條邊,因此它的時間複雜度與圖形的大小成正比。 ### 空間複雜度 $O(V)$ 因為`BFS` 使用了一個佇列來保存尚未探索的節點,其中 `V` 是節點的數量。在最壞的情況下,`BFS` 需要將圖形中的每個節點都加入佇列,因此空間複雜度也與圖形的大小成正比。 ## 實戰 [637. Average of Levels in Binary Tree](https://leetcode.com/problems/average-of-levels-in-binary-tree/description/) ### 題目說明 給定一棵二元數,以數組的形式返回每一層節點的平均值。實際答案在 $10^5$ 以內的答案將被接受。 ![](https://i.imgur.com/zVaU74w.jpg) ### 解法 使用佇列方式層次遍歷,並累加每一層節點的值,計算出每一層節點的平均值,並儲存於陣列中傳回。 ```javascript= /** * Definition for a binary tree node. * function TreeNode(val, left, right) { * this.val = (val===undefined ? 0 : val) * this.left = (left===undefined ? null : left) * this.right = (right===undefined ? null : right) * } */ /** * @param {TreeNode} root * @return {number[]} */ var averageOfLevels = function(root) { let queue = [root]; let target = []; while (queue.length > 0) { let qlen = queue.length; let row = 0; for (let i = 0; i < qlen; i++) { let {val, left, right} = queue.shift(); row += val; if (left) queue.push(left); if (right) queue.push(right); } target.push(row/qlen); } return target; }; ```