1.深度優先遍歷過程
深度優先遍歷適用於有向圖和無向圖
複雜度:鄰接表:O(V+E) 鄰接矩陣:O(V^2)
過程:
訪問0: 訪問0的第一個相鄰結點1
訪問1:1的相鄰結點爲0,訪問過了,結點1的全部相鄰結點訪問完畢,退回0
接着訪問0的下一個相鄰結點2
訪問2:2的相鄰結點爲0,訪問過了,結點2的全部相鄰結點訪問完畢,退回0
接着訪問0的下一個相鄰結點5
訪問5:5的第一個相鄰結點爲0,訪問過了,訪問下一個結點3
訪問3: 3的第一個相鄰結點爲4
訪問4:4的第一個相鄰結點爲3,訪問過了,下一個相鄰結點5,訪問過了,相鄰結點6
訪問6:6的兩個相鄰結點都已經訪問過了,退回4
按照這樣的方式訪問下去,直到將0的全部相鄰結點訪問完
2.求一個圖的連通分量
使用深度優先遍歷可以很容易的得到全部和點i相通的點。
計算一個圖有多少個連通分量:可以選取一個沒有遍歷過的點,一直遍歷到沒有結點訪問爲止,再找下一個圖中沒有遍歷過的點,循環這種過程,直到把所有結點都遍歷完,這樣就可以計算出圖有多少個連通分量
判斷兩個點是否連通:使用一個id數組,對結點進行標記,連通的兩個結點的id值相等。id可以使用當前連通分量個數表示
所有,第一個連通分量id=0,第二個連通分量id=1,第三個連通分量id=2
3.代碼實現
使用一個visited數組來表示結點是否被訪問過
深度優先遍歷:dfs()函數,將結點的visited設置爲true,遍歷結點i的全部鄰接結點,如果找到一個鄰接結點j還沒有被訪問過:dfs(j)
求連通分量:遍歷全部結點,如果結點i沒有被訪問過,dfs(i),count++;
#include<iostream>
#include<vector>
using namespace std;
//圖的深度優先遍歷
class Graph{
public:
int n;//結點數
vector<vector<int> > g;//使用鄰接表表示一張圖
bool directed;//是否是有向圖
Graph(int n,bool directed){
this->n = n;
this->directed = directed;
for(int i=0; i<n; i++)
g.push_back(vector<int>());
}
//添加一條邊
void addEdge(int v, int w)
{
g[v].push_back(w);
if(!directed)
g[w].push_back(v);
}
void print()
{
for(int i=0; i<n; i++)
{
cout<<i<<":";
for(int j=0; j<g[i].size(); j++)
cout<<g[i][j]<<" " ;
cout<<endl;
}
}
};
int n=7;
Graph g1(n,false);
vector<bool> visited(n,false); //標記結點是否被訪問過
int ccount=0;//連通分量
vector<int> id(n,-1); //標記結點屬於哪個連通分量
//深度優先遍歷,從i結點開始進行深度優先遍歷
void dfs(int i)
{
id[i] = ccount;
visited[i]=true;
cout<<i<<" ";
//遍歷結點i的全部相鄰結點
for(int j=0;j<g1.g[i].size(); j++)
{
if(!visited[g1.g[i][j]])
dfs(g1.g[i][j]);
}
}
int main()
{
g1.addEdge(0,1);
g1.addEdge(0,2);
//g1.addEdge(0,5);
g1.addEdge(0,6);
g1.addEdge(3,4);
g1.addEdge(5,3);
g1.addEdge(5,4);
//g1.addEdge(4,6);
g1.print();
cout<<endl;
cout<<"深度優先遍歷:";
dfs(0);//深度優先遍歷
cout<<endl;
//計算連通分量
for(int i=0; i<n; i++)
visited[i]=false;
//遍歷每個結點,如果未被訪問過,則dfs一次
for(int i=0; i<n; i++)
{
if(!visited[i])
{
dfs(i);
cout<<endl;
ccount++;
}
}
cout<<"連通分量個數:"<<ccount<<endl;
//判斷兩個結點是否連通
cout<<(id[3]==id[1])<<endl;
cout<<(id[3]==id[5])<<endl;
return 0;
}