本文介紹圖的兩種重要遍歷算法:深度優先搜索與廣度優先搜索
一.深度優先搜索(DFS)
深度優先搜索是一個不斷探查與回溯的過程,其思想是遞歸。樹的先序遍歷可以看成是深度優先搜索的一種情況。在探查的每一步中,算法都記錄有一個當前頂點。最初的當前頂點,也即函數指定的開始頂點。在每一步的探查過程中,首先訪問當前頂點v,並立刻將其訪問標志visited[v]設為true。然后將與其鄰接的任一還未訪問過的頂點作為當前頂點,重復上述步驟。當當前頂點的的所有鄰接頂點均已訪問過后,退回到上一步時訪問的頂點,並將其設為當前頂點,繼續探查其是否還有未訪問過的頂點。當所有頂點的visited均已設為true時,證明該連通圖的所有頂點均已至少訪問一遍,此時遞歸工作棧逐步退棧,程序結束。
給出一個用DFS遍歷的示例:
給出圖(a)的以0為最初頂點的DFS的工作過程:
從頂點0開始進行的深度優先遍歷過程:0,1,(0),3,(1),7,(3),4,(1),(7),(back to 7),5,2,(0),6,(2),(7),(back to 2),(5),(back to 5),(7),(back to 4),(back to 7),(5),(6),(back to 3),(back to 1),(4),(back to 0),(2)end;
DFS的偽代碼描述:
virtual void Graph::DFS(){
bool* visited=new bool[n];
for(int i=0;i<n;i++)
visited=false;
DFS(0);
delete []visited;
}
virtual void Graph::DFS(const int v){ //訪問當前頂點v的所有未訪問過的結點
visited[v]=true;
for(each vertex w adjacent to v)
DFS(w);
}
代碼實現:
void DFS(Graphlnk& G, const int v) {
int loc;
int n = G.NumberOfVertex(); //圖中頂點個數
bool* visited = new bool[n];
for (int i = 0; i < n; i++)
visited[i] = false;
loc = G.GetVertexPos(v); //獲取v對應的結點在圖中的位置
DFS(G, loc, visited); //遞歸子程序
delete[]visited;
}
void DFS(Graphlnk& G, const int v, bool* visited) {
std::cout << G.getValue(v) << " ";
visited[v] = true;
int w = G.getFirstNeighbor(v); //獲取v的第一個鄰接結點
while (w != -1) {
if (visited[w]==false)
DFS(G, w, visited);
w = G.getNextNeighbor(v, w); //獲取v的鄰接結點的下一個鄰接結點
}
}
其中的圖由鄰接表實現;
DFS時間復雜度的分析:初始化標志數組visited[]的時間復雜度為O(n);
如果圖以鄰接矩陣的形式表示,那么探查當前頂點v的所有鄰接結點的時間復雜度為O(n),因為需要遍歷矩陣第v行的n個結點;由於有n個頂點,故總體時間復雜度為O(n²)
如果圖以鄰接鏈表的形式表示,則只要遍歷當前頂點的鏈表即可,DFS訪問每一個頂點最多一次,若圖一共有e條邊,時間復雜度為O(e+n).
二.廣度優先搜索
與DFS不同,廣度優先搜索(BFS)不是一個探查與回溯的過程,而是一個層次遍歷的過程。在這個過程中,圖有多少頂點就要重復多少步,每一步都有一個當前頂點。最初的當前頂點是由主過程指定的當前頂點。在每一步中,首先訪問當前頂點v,並設置該頂點的訪問標志visited為true,然后依次訪問當前頂點的所有鄰接頂點w1,w2,......wn,然后再按順序依次訪問w1,w2,......wn所有未訪問的鄰接頂點,依次類推直到圖中的所有結點都被訪問。
由於BFS不是一個遞歸的過程,故需要一個隊列來記錄正在訪問的這一層以及上一層頂點,以便於繼續向下訪問。
依舊以上圖(a)為例,我們給出其廣度優先遍歷的序列:
0,1,2,3,4,5,6,7
BFS的偽代碼描述:
virtual void Graph::BFS(int v){
bool* visited=new bool[n];
fill(visited,visited+n,false);
queue<int>Q;
Q.push(v);
visited[v]=true;
while(!Q.empty()){
v=Q.front();
Q.pop();
for (all vertices w adjacent to v)
if(!visited[w]){
Q.push(w);
visited[w]=true;
}
}
delete []visited;
}
代碼實現:
void BFS(Graphlnk& G, const int v) {
int w;
int n = G.NumberOfVertex();
bool* visited = new bool[n];
for (int i = 0; i < n; i++)
visited[i] = false;
int loc = G.GetVertexPos(v);
std::cout << G.getValue(loc) << " ";
visited[loc] = true;
std::queue<int>Q;
Q.push(loc);
while (!Q.empty()) {
loc = Q.front();
Q.pop();
w = G.getFirstNeighbor(loc);
while (w != -1) {
if (visited[w]==false) {
std::cout << G.getValue(w) << " ";
visited[w] = true;
Q.push(w);
}
w = G.getNextNeighbor(loc, w);
}
}
delete[]visited;
}
時間復雜度:同DFS;