圖的深度優先遍歷和計算連通分量

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;
	
} 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章