图论入门、图的dfs、bfs模板

本文适合图论初学者,详细介绍了图的概念,包括有向图、无向图和树的定义,并对比了邻接矩阵与邻接表两种图的表示方法,重点讲解了如何使用vector或ArrayList建立邻接表。此外,还提供了图的深度优先搜索(DFS)和广度优先搜索(BFS)的模板,帮助理解这两种图的遍历算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文适用于对图论代码实现不了解的初学者。

图的概念

所谓图,即一些顶点和边的集合。其中点的位置、边的形状是无所谓的,重点研究的是点和边的关系。
在图中,一条边仅能连接2个点。边分为有向边(单向连接)和无向边(双向连接)
有向图:边为有向边的图。
无向图:边为无向边的图。
树:边数=顶点数-1的无向连通图。

图的建立

图有两种表示方法:邻接矩阵和邻接表。

邻接矩阵指:对于一个n个顶点的图,建立一个n*n的二维矩阵g[n][n],其中g[i][j]可以按照自己的选择定义:对于无权图,1代表i到j有一条有向边,0代表i到j没有边。对于带权图,a[i][j]=x代表i到j有一条权值为x的边。
如果是无向图,可以让a[i][j]=a[j][i]=x代表i和j连接了一条权值为x的边。
邻接矩阵存在一些缺陷:第一是如果是稀疏矩阵(边数远小于点数的平方),会存在大量的0,浪费了大量的空间,如果n较大时,二维矩阵就无法存储。第二是如果有重边的话(如i到j有两条不同的有向边相连),邻接矩阵将无法存储。

这里介绍一下邻接表。所谓邻接表,指对于n个顶点,先设置n条空链表,假设引进了i到j的一条边,那么在第i个链表上新增一个节点来描述这条边的信息。由于链表占据的空间是可变的,因此这种存图的方法方便存储稀疏矩阵(尤其是树的建立)。

使用vector数组或ArrayList数组建立邻接表

c++里stl标准库的vector工具、java里util包中的ArrayList都是可变长度的数组,可以用来建立邻接表。

vector的说明

需要#include<vector>头文件。
vector<int>a; //vector的声明。等价于int a[n]
a.size() //表示a中的元素个数
a.push_back(i) //在a的最后一个元素后面增加新元素i
a.pop_back() //删除a的最后一个元素
a[i] //表示a的第i个元素。a的所有元素是从a[0] 到a[a.size()-1],这一点和数组是一样的。

ArrayList的说明

需要import java.util.ArrayList;导入相关包。
ArrayList<Integer>list=new ArrayList<Integer>(100010); //实例化
list.size() //list中的元素个数。
list.add(x) //最后一个元素之后添加新元素x
list.get(i) //获取第i个元素,所有元素下标是从0到list.size()-1

用vector建立邻接表的示例

输入:
第一行两个正整数n和m,代表顶点数和边数。
接下来的m行,每行两个正整数x和y,代表x到y之间有一条无向边。
样例输入:
3 2
1 2
1 3

vector<int>g[100010]		//建议使用全局变量。
int n,m;
int main(){
 	cin>>n>>m;
 	while(m--){ 
 		int x,y;
 		cin>>x>>y;
 		g[x].push_back(y);
 		g[y].push_back(x);	//如果是x到y的有向边,则不要这句。
 	}
}

图的dfs模板

int visited[100010];		//全局变量,标记数组。
void dfs(int x){
 	int i;
 	for(i=0;i<g[x].size();i++){	//用了全局变量,这里不用参数传入。
 		if(!visited[g[x][i]]){
			visited[g[x][i]]=1;
			dfs(g[x][i]);
 		}
 	}
}

图的bfs模板

int visited[100010];		//全局变量,标记数组。
void bfs(){
 	queue<int>q;		//使用队列辅助bfs。
 	q.push(1); 
 	visited[1]=1;
 	while(!q.empty()){
 		int temp=q.front();
 		for(int i=0;i<g[temp].size();i++){
 			if(!visited[g[temp][i]]){
 				visited[g[temp][i]]=1;
 				q.push(g[temp][i]);
 			}
 		}
 		q.pop();
 	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值