图的深度优先遍历和计算连通分量

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

 

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