c++ 图DFS遍历, 及获取连通量(可用于判断两点间的可达性)

数据结构-图


前言

图是一种挺复杂的数据结构,在此介绍一下图的遍历以及连通分量的求法:


一、连通分量是什么?

我们在次不做定义的介绍,用通俗的语言:
	连通分量可以理解为:图可以分为 互相没有联系的几个部分:
如下图:
	第一张图片里面节点全相通(从任意一个节点都有路径到其他节点),所以称其连通分量为1
	第二张图里面显然可以分为两个部分,连通分量为2

在这里插入图片描述
在这里插入图片描述

二、图的相关操作

1. 存储的实现(邻接表)

我们利用以下结构进行存储图相关信息:
const int N = 10001;
vector<int> g[N];

2.读入数据

n代表节点的个数, m代表路径的条数;
a , b 接收的是两个相通的节点编号信息;
测试数据(6个节点,8条边,后面8行代表:边的端点信息(编号0到5)):
6 8
0 1
0 2
0 5
1 2
1 3
1 4
3 4
3 5

代码如下:

#include<bits/stdc++.h>

using namespace std;
const int N = 10001;

vector<int> g[N];

int main(){
	int n , m;
	cin >> n >> m;
	memset(id , -1 , sizeof(id));
	memset(visited , false , sizeof(visited));
	for(int i = 0 ; i < m ; i++){
		int a , b;
		cin >> a >> b;
		g[a].push_back(b);
		g[b].push_back(a);
	}
}

2.图的遍历(递归实现DFS)

在此我们使用深度优先(DFS)进行遍历(递归实现):
我们需要一个visisted[]数组来标识对应下标节点是否被访问过;

代码如下:

void dfs(int v){
	visited[v] = true;//标注为已访问
	//进行遍历此节点可以达到的节点(联通的)
	for(int i = 0 ; i < g[v].size() ; i++){
		if(!visited[g[v][i]]){//节点没被访问过
			dfs(g[v][i]);//进行访问
		}
	}
} 

3. 连通分量的求解

连通分量的求解很简单:
	我们对所有的节点依次进行DFS访问,在对第一个节点DFS的时候,我们可以得到此节点可以达到的所有节点的信息,我们标记为 已访问 ;
	 如果一轮结束后 , 还有没被访问过的节点, 再次对其进行访问,并且连通分量+1即可:

代码如下:

	for(int j = 0 ; j < n ; j++){//遍历所有节点
		if(visited[j] == 0){//节点没被访问
			dfs(j);//访问
			count2++;//连通分量加一
		}
	}

4. 连通分量判断两点是否可达

我们用id[]数组来标注节点对应的连通分量的编号(相当于给此节点在哪一个联通的图做了标记)
最后只需要判断两个节点是否在一个连通图里即可
bool isConnected(int a , int b){
	return id[a] == id[b];
}
#include<bits/stdc++.h>

using namespace std;
const int N = 10001;

vector<int> g[N];

int visited[N] = {0};
int id[N];
int count2 = 0;

void dfs(int v){
	visited[v] = true;
	id[v] = count2;//在一个连通图里的获得相同编号
	for(int i = 0 ; i < g[v].size() ; i++){
		if(!visited[g[v][i]]){
			dfs(g[v][i]);
		}
	}
} 

//判断两点是否连通
bool isConnected(int a , int b){
	return id[a] == id[b];
}

int main(){
	int n , m;
	cin >> n >> m;
	memset(id , -1 , sizeof(id));
	memset(visited , false , sizeof(visited));
	for(int i = 0 ; i < m ; i++){
		int a , b;
		cin >> a >> b;
		g[a].push_back(b);
		g[b].push_back(a);
	}
	
	for(int j = 0 ; j < n ; j++){
		if(visited[j] == 0){
			dfs(j);
			count2++;	
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值