1. 程式人生 > >圖論算法之DFS與BFS

圖論算法之DFS與BFS

nod pty pop 直觀 遍歷 必須掌握 取出 二分 最短

  • 概述(總)
DFS是算法中圖論部分中最基本的算法之一。對於算法入門者而言,這是一個必須掌握的基本算法。它的算法思想可以運用在很多地方,利用它可以解決很多實際問題,但是深入掌握其原理是我們靈活運用它的關鍵所在。
  • 含義特點
DFS即深度優先搜索,有點類似廣度優先搜索,也是對一個連通圖進行遍歷的算法。它的思想是從一個頂點V0開始,沿著一條路一直走到底,如果發現不能到達目標解,那就返回到上一個節點,然後從另一條路開始走到底,這種盡量往深處走的概念即是深度優先的概念。 由於用到遞歸,當節點特別多且深度很大的時候,可能會發生棧溢出。解決辦法是將遞歸改為非遞歸,自行編寫棧。 BFS即廣度優先搜索(也稱寬度優先搜索),是連通圖的一種遍歷策略。因為它的思想是從一個頂點V0開始,輻射狀地優先遍歷其周圍較廣的區域,故得名。 一般可以用它做什麽呢?一個最直觀經典的例子就是走迷宮,我們從起點開始,找出到終點的最短路程,很多最短路徑算法就是基於廣度優先的思想成立的。
  • 應用場景
  • dfs
  1. 連通分量
連通分量:任意兩點可互達的圖。 求無向圖的連通分量:O(n)
  1. 二分圖判定
二分圖:每條邊的兩個節點分別著不同的兩種顏色。 判斷一個圖是否是二分圖:O(n)
  1. 二叉樹的遞歸遍歷
  • bfs
  1. 求割頂和橋
割頂:對於無向圖G,如果刪除某點u後,連通分量數目增加,則u即割頂。 橋:對於無向圖G,如果刪除某點邊e後,連通分量數目增加,則e即橋。 求所有的圖中的割頂和橋: 方式一:嘗試刪除每個節點,用dfs判斷連通分量是否增加。時間復雜度:O(n(n+m))。 方式二:給每個節點記錄兩個時間戳,深入挖掘dfs。時間復雜度:O(n+m)。

  2.二叉樹的層次遍歷

  • 代碼實現
/**
* DFS核心偽代碼
* 前置條件是visit數組全部設置成false
* @param n 當前開始搜索的節點
* @param d 當前到達的深度
* @return 是否有解
*/
bool DFS(Node n, int d){
if (isEnd(n, d)){//一旦搜索深度到達一個結束狀態,就返回true
return true;
}
for (Node nextNode in n){//遍歷n相鄰的節點nextNode
if (!visit[nextNode]){//
visit[nextNode] = true;//在下一步搜索中,nextNode不能再次出現
if (DFS(nextNode, d+1)){//
如果搜索出有解 //做些其他事情,例如記錄結果深度等 return true; } //重新設置成false,因為它有可能出現在下一次搜索的別的路徑中 visit[nextNode] = false; } } return false;//本次搜索無解 }
/**
* 廣度優先搜索
* @param Vs 起點
* @param Vd 終點
*/
bool BFS(Node& Vs, Node& Vd){
queue<Node> Q;
Node Vn, Vw;
int i;
 
//初始狀態將起點放進隊列Q
Q.push(Vs);
hash(Vw) = true;//設置節點已經訪問過了!
 
while (!Q.empty()){//隊列不為空,繼續搜索!
//取出隊列的頭Vn
Vn = Q.front();
 
//從隊列中移除
Q.pop();
 
while(Vw = Vn通過某規則能夠到達的節點){
if (Vw == Vd){//找到終點了!
//把路徑記錄,這裏沒給出解法
return true;//返回
}
 
if (isValid(Vw) && !visit[Vw]){
//Vw是一個合法的節點並且為白色節點
Q.push(Vw);//加入隊列Q
hash(Vw) = true;//設置節點顏色
}
}
}
return false;//無解
}

  • 總結(總)
  • DFS適合此類題目:給定初始狀態跟目標狀態,要求判斷從初始狀態到目標狀態是否有解。
  • BFS適合此類題目:給定初始狀態跟目標狀態,要求從初始狀態到目標狀態的最短路徑。
  • 參考資料
http://rapheal.iteye.com/blog/1526863 http://blog.csdn.net/u011437229/article/details/53188837 http://www.cnblogs.com/George1994/p/6346751.html

圖論算法之DFS與BFS