演算法之BFS演算法框架
阿新 • • 發佈:2021-01-04
作者的話:最近有點時間,開始回來寫寫演算法相關的文章
BFS演算法框架
前言
BFS(廣度優先順序搜尋)和DFS(深度優先順序搜尋)是比較常用的演算法,其中DFS算是一種回溯演算法,在二叉樹中就相當於前序遍歷演算法。這裡先分析BFS演算法,為什麼呢?因為BFS比較簡單!廢話少說,直接上分析!
演算法分析
BFS相對於DFS最主要的區別在於:BFS找到的路徑一定是最短的,但是空間複雜度比DFS要大很多。
BFS演算法的核心思想實際上就是將問題抽象成“圖”,從一個點開始,向周圍擴散。一般來說,我們寫BFS演算法常用的資料結構是“佇列”,每次都將一個節點周圍的所有節點加入佇列。
BFS演算法是出現的場景實際上就是讓你在一幅“圖”裡面找出從“起點”到“終點”的最短距離。把演算法本質搞清楚之後,問題都能化歸為基本問題。
如果上面的分析有點枯燥?不要緊,直接上栗子:
如走迷宮,有的格子周圍的牆壁不能走,讓你算從起點到終點的最短距離是多少?如果這個迷宮某些格子有“傳送門”呢?
再比如有兩個單詞,要求通過替換某些字母,把其中一個變成另外一個,每次只能替換一個字母,最少要替換幾次?
再比如連連看遊戲,消除兩個方塊的條件不僅僅是圖案相同,還要保證兩個方塊之間的最短連線不能多於兩個兩個拐點。你玩連連看,點選兩個座標,程式是如何找到最短連線的?如何判斷最短連線有幾個拐點?
。。。
其實,上面的例子無一不是一幅“圖”,讓你從起點走到終點,問最短路徑,實則BFS本質。
BFS演算法框架
上面分析完了,下面直接上演算法框架虛擬碼:
// 計算從起點 start 到終點 target 的最近距離 int BFS(Node start, Node target) { Queue<Node> q; // 核心資料結構 Set<Node> visited; // 避免走回頭路 q.offer(start); // 將起點加入佇列 visited.add(start); int step = 0; // 記錄擴散的步數 while (q not empty) { int sz = q.size(); /* 將當前佇列中的所有節點向四周擴散 */ for (int i = 0; i < sz; i++) { Node cur = q.poll(); /* 劃重點:這裡判斷是否到達終點 */ if (cur is target) return step; /* 將 cur 的相鄰節點加入佇列 */ for (Node x : cur.adj()) if (x not in visited) { q.offer(x); visited.add(x); } } /* 劃重點:更新步數在這裡 */ step++; } }
記住:因為BFS都是每次都是所有節點一起遍歷,因此BFS總能比較快地找到最短路徑。