關於圖的遍歷,通常有深度優先搜索(DFS)和廣度優先搜索(BFS),本文結合一般的圖結構(鄰接矩陣和鄰接表),給出兩種遍歷算法的模板
1.深度優先搜索(DFS)
#include<iostream>
#include<unordered_map>
#include<queue>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<sstream>
#include<set>
#include<map>
using namespace std;
#define VERTEX_SIZE 100 //定義圖中頂點數目
bool visited[VERTEX_SIZE];//建立頂點標記數組,用於判斷頂點是否已經走過
class Graph{
.... //自定義圖結構(鄰接矩陣或者鄰接表)
};
void DFSTraverse(Graph G)
{
memset(visited,false,sizeof(visited));//初始化頂點標記數組
for(int i = 0 ; i < VERTEX_SIZE;i++) //遍歷圖中的每個連通分量
if(!visited[i])
DFS(G,i);
}
void DFS(Graph G,int v)
{
visited[v] = true;//修改標記
visit(v);//訪問頂點v
for(int w = FirstAdjVex(G,v); w >= 0;w = NextAdjVex(G,v,w))//尋找頂點v的鄰接點
if(!visited[w])
DFS(G,w);
}
void visit(int v)
{
//自定義操作
;
}
int main()
{
...
}
關於這個模板,有幾點需要注意的:
(1)此處的模板適用於以鄰接表表示的圖結構或者以鄰接矩陣表示的圖結構,若以鄰接表表示的話,時間復雜度為O(n+e);若以鄰接矩陣表示的話,時間復雜度為O(n^2)。其中n為圖中節點的個數,e為邊的個數。
(2)遍歷圖的限制條件比較少,只要是未訪問過(visited[v] == false)就可以進行訪問。
(3)尋找頂點v的鄰接點那部分代碼是偽代碼,需要根據圖的具體表示結構進行尋找(鄰接矩陣找到相應行進行遍歷;鄰接表遍歷相應的單鏈表)
(4)在函數DFSTraverse()中,加入了個for循環,目的是:如果圖是非連通圖的話,需要遍歷每個連通分支。由此,可以利用DFS來判斷圖的連通性,如果從某個節點開始遍歷(任意節點),能遍歷到所有節點的話,俺么這個圖就是連通的。相當於在上述模板中把DFSTraverse()函數中的for循環換成單次遍歷。(參考《王道》P191)
2.廣度優先搜索(BFS)
#include<iostream>
#include<unordered_map>
#include<queue>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<sstream>
#include<set>
#include<map>
using namespace std;
#define VERTEX_SIZE 100 //定義圖中頂點數目
bool visited[VERTEX_SIZE];//建立頂點標記數組,用於判斷頂點是否已經走過
class Graph{
....//自定義圖結構(鄰接矩陣或者鄰接表)
};
void BFSTraverse(Graph G)
{
memset(visited,false,sizeof(visited));//初始化頂點標記數組
queue<int> Q;
for(int i = 0 ; i < VERTEX_SIZE;i++)
if(!visited[i])
BFS(G,i,Q);
}
void BFS(Graph G,int v,queue<int> &Q)
{
visited[v] = true;
visit(v);//訪問頂點v
Q.push(v);//v入隊
while(!Q.empty())
{
int u = Q.front();
Q.pop();
for(int w = FirstAdjVex(G,u); w >= 0;w = NextAdjVex(G,u,w))//找到頂點w的所有鄰接點
if(!visited[w])//訪問w的鄰接點,並且訪問過后將鄰接點入隊
{
visited[w] = true;
visit(w);
Q.push(w);
}
}
}
void visit(int v)
{
//自定義操作
;
}
int main()
{
...
}
(1)BFS的時間復雜度與DFS是一樣的。
(2)BFSTraverse()函數中的for循環和DFSTraverse()中的作用是一樣的,都是遍歷所有的連通分支,只不過遍歷的順序不同;所以同樣可以用BFS來判斷圖的連通性。
(3)隊列存儲的頂點都是它們本身已經訪問過的但它們的鄰接點未被訪問過。
