前言
這幾天復習圖論算法,覺得BFS和DFS挺重要的,而且應用比較多,故記錄一下。
廣度優先搜索
有一個有向圖如圖a
圖a
廣度優先搜索的策略是:
從起始點開始遍歷其鄰接的節點,由此向外不斷擴散。
1.假設我們以頂點0為原點進行搜索,首先確定鄰接0的頂點集合S0 = {1,2}。
2.然后確定頂點1的集合S1 = {3},頂點2沒有鄰接點,所以集合為空。
3.然后確定3的鄰接點集合S3,因為2已經被遍歷過,所以不考慮,所以由頂點3知道的鄰接點集合S3 = {4}。
4.然后再確定頂點4的鄰接點集合,頂點4沒有更多的鄰接點了,此時也沒有還未遍歷的鄰接點集合,搜索終止。
遍歷的路徑可以參考如下圖紅色標記的路徑:
動態過程
代碼的實現思路:
BFS()
{
輸入起始點; 初始化所有頂點標記為未遍歷; 初始化一個隊列queue並將起始點放入隊列; while(queue不為空) {
從隊列中刪除一個頂點s並標記為已遍歷; 將s鄰接的所有還沒遍歷的點加入隊列; }
}
深度優先遍歷
繼續以圖a為例
圖a
深度優先遍歷的策略是:
從一個頂點v出發,首先將v標記為已遍歷的頂點,然后選擇一個鄰接於v的尚未遍歷的頂點u,如果u不存在,本次搜素終止。如果u存在,那么從u又開始一次DFS。如此循環直到不存在這樣的頂點。
比如圖a中
1.從頂點0開始,將0標記為已遍歷,然后選擇未被遍歷的鄰接0的頂點1。
2.標記頂點1,然后選擇3並標記,然后選擇頂點3鄰接的頂點2。
3.頂點2標記后沒有與它鄰接的未標記的點,所以返回3選擇另一個鄰接3並且未被標記的頂點4。
4.頂點4沒有更多的符合條件的點,因此搜索終止,返回到3,3沒有更多的點,搜索終止返回到1,最后返回到0,搜索終止。
遍歷的路徑可以參考如下圖紅色標記的路徑:
動態過程
代碼的實現思路:
DFS(頂點v) { 標記v為已遍歷; for(對於每一個鄰接v且未標記遍歷的點u) DFS(u); }
一個簡單的應用
問題不贅述,具體可參考 LeetCode朋友圈問題 。
實現的代碼如下(C#):
public class Solution { public void dfs(int [,]M,int []visit,int i) { for(int j = 0;j < M.GetLength(0);j++) { if(M[i,j] == 1 && visit[j] == 0) { visit[j] = 1; dfs(M,visit,j); } } } public void bfs(int [,]M,int []visit,int i) { Queue<int> q = new Queue<int>(); q.Enqueue(i); while(q.Count > 0) { int temp = q.Dequeue(); for(int j = 0;j < M.GetLength(0);j++) { if(M[temp,j] == 1 && visit[j] == 0) { visit[j] = 1; q.Enqueue(j); } } } } public int FindCircleNum(int[,] M) { int N = M.GetLength(0); int circle = 0; //朋友圈數 int[] visit = new int[N]; for(int i = 0;i < N;i++) { if(visit[i] == 0) //還沒被遍歷過 { //dfs(M,visit,i); //使用dfs搜索並標記與其相關的學生 bfs(M,visit,i); //使用bfs搜索並標記與其相關的學生 circle++; } } return circle; } }
參考資料
《數據結構、算法與應用——C++描述》 作者:【美】 薩特吉·薩尼 機械工業出版社