一、介紹
深度優先遍歷(Depth First Search)的主要思想是首先以一個未被訪問過的頂點作為起始頂點,沿當前頂點的邊走到未訪問過的頂點。當沒有未訪問過的頂點時,則回到上一個頂點,繼續試探別的頂點,直至所有的頂點都被訪問過。
聯通分量,無向圖 G 的一個極大連通子圖稱為 G 的一個連通分量(或連通分支)。連通圖只有一個連通分量,即其自身;非連通的無向圖有多個連通分量。連通分量與連通分量之間沒有任何邊相連。深度優先遍歷可以用來求連通分量。
下圖有3個聯通分量:
二、遍歷過程
如下圖:
以鄰接表為例
遍歷過程中需要注意的是:遍歷到x節點時,同樣遍歷方向會向第x行移動,如果x行為空,則會返回到原來的行
從0開始遍歷:(0遍歷完後向第0行繼續遍歷)
然後遍歷1:(遍歷1時已經在第1行,)
遍歷第1行時,第1行後續只有0(0已被遍歷然後返回第0行),所以開始遍歷2(同時遍歷方向也向第2行)
同理
返回到了第0行,遍歷5,同時遍歷方向變成了第5行
第5行的後續第一個節點是0(已被遍歷),接著往後走就是節點3
遍歷完節點3後,看第3行的後續是節點4,遍歷節點4
同理現在就該遍歷6了
至此圖的遍歷就完成了
三、程式碼實現
#include <iostream>
#include <cassert>
using namespace std;
//求無權圖的聯通分量
template <typename Graph>
class Component{
private:
Graph &G; //圖的引用
bool *visited; //記錄深度遍歷已經被訪問過的節點
int ccount; //記錄聯通分量
int *id; //每個節點對應的聯通分量
//dfs遍歷
void dfs(int v){
visited[v] = true;
id[v] = ccount;
//傳入迭代器
typename Graph::adjIterator adj(G, v);
for(int i = adj.begin(); !adj.end(); i = adj.next()){
if(!visited[i]){
dfs(i);
}
}
}
public:
//建構函式,求無權圖的聯通分量
Component(Graph &graph):G(graph){
//演算法初始化
id = new int[G.V()];
visited = new bool[G.v()];
ccount = 0;
for(int i = 0; i < G.v(); i++){
visited[i] = false;
id[i] = -1;
}
for(int i = 0; i < G.v(); i++){ //對子圖的遍歷
//如果visited[i]沒有被訪問過
if(!visited[i]){
dfs(i);
ccount ++;
}
}
}
//解構函式
~Component(){
delete[] visited;
delete[] id;
}
//返回圖的聯通分量
int count(){
return ccount;
}
//查詢v和w是否聯通
bool isComponent(int v, int w){
assert( v >= 0 && v < G.V() );
assert( w >= 0 && w < G.V() );
return id[v] = id[w];
}
};
本作品採用《CC 協議》,轉載必須註明作者和本文連結