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