当前位置: 首页 > news >正文

蓝桥杯备考---- 图的存储与遍历

图的存储方法有两种,首先就是邻接矩阵

那,什么是邻接矩阵呢,邻接矩阵就是用一个二维数组存储两个结点的邻接关系的一个矩阵

光说可能有的人不懂,我们在图上解释吧

如图,结点之间没有边的地方全部设为无穷大,1,2表示1到2有一个边,权值就是a[1][2],无向图的话,a[1][2]存一个权值,a[2][1]要存相同的权值;

这就是邻接矩阵,把所有结点之间边的情况存在一个二维数组里,这个二维数组的大小应该是a[N][N] N表示结点个数

也就是空间复杂度为n²,n为结点个数,跟边数无关,适合存储边数多的图,也就是稠密图

#include <iostream>
using namespace std;
const int N = 1010;
int n,m;
int edges[N][N];
int main()
{
	int n,m;cin >> n >> m;//结点个数和边的个数 
	//刚开始的时候设置每个结点之间都没有边,嗯。。就设成负无穷好了
	memset(edges,-0x3f,sizeof edges);
	
	for(int i = 1;i<=m;i++)
	{
		int a,b,c;cin >> a >> b >> c;//ab表示两个结点
		edges[a][b] = c;
		edges[b][a] = c;//如果是无向边,相反的情况也要存一下 
		
	}	
	
	
	
	
	
	return 0;
}

另一种存储方式就是邻接表了,这种存储方式就是开一个vector数组,然后每个结点都把他有边的结点存起来,但是,光存结点肯定是不行的,这时候我们可以用一个pair类型来存另一个结点以及边的权值

这个就很像我们之前学树的时候的孩子表示法

#include <iostream>
#include <vector>
using namespace std;
const int N = 1010;
int n,m;
typedef pair<int,int> PII;
vector <PII> edges[N];
int main()
{
	int n,m;cin >> n >> m;//结点个数和边的个数 
	
	for(int i = 1;i<=m;i++)
	{
		int a,b,c;cin >> a >> b >> c;//ab表示两个结点
		edges[a].push_back({b,c});
		edges[b].push_back({a,c});
		
	}	
	
	
	
	
	
	return 0;
}

当然啦,我们的邻接表除了这种形式存之外,还有别的存储方式,我们还可以用链式前向星来存储

#include <iostream>
#include <vector>
using namespace std;
const int N = 1010;
int n,m;
int h[N],e[2*N],ne[2*N],w[N*2],id;
void add(int a,int b,int c) //把b结点头插到a结点后面的链表里
{
	id++;
	e[id] = b;
	ne[id] = h[a];
	h[a]=id;
	w[id] = c;
	
 } 
int main()
{
	int n,m;cin >> n >> m;//结点个数和边的个数 
	
	for(int i = 1;i<=m;i++)
	{
		int a,b,c;cin >> a >> b >> c;//ab表示两个结点
		add(a,b,c);//把b头插到a的结点里面  
		add(b,a,c);//把a头插到b的结点里面 
	}	
	
	
	
	
	
	
	return 0;
}

好的,这就是我们的几种存储方法,接下来我们还得继续介绍一下图是怎么遍历的

老样子,我们还是分为dfs和bfs遍历

我们先说一下dfs

一路走到黑我们先看邻接矩阵怎么遍历

#include <iostream>
using namespace std;

const int N = 5001;
bool st[N];
int edges[N][N];
void dfs(int u)
{
	cout << u << " ";
	st[u] = true;
	for(int v = 1;v<=n;v++)
	{
		if(edges[u][v]!=-1 && !st[v])
		{
			dfs(v);
		}
	 } 
}
int main()
{
	int n,m; cin >> n >> m;
	memset(edges,-1,sizeof(edges));
	for(int i = 1;i<=m;i++)
	{
		int a,b,c;
		cin >> a >> b >> c;
		edges[a][b] = c;
		edges[b][a] = c;
		
	}

	
	
	
	
	return 0;
}

接下来看看邻接表怎么遍历

#include <iostream>
#include <vector>
using namespace std;

const int N = 5001;
typedef pair<int,int> PII;
bool st[N];
vector <PII> ret[N];
void dfs(int u)
{
	cout << u << " ";
	st[u] = true;
	for(auto &e : ret[u])
	{
		int x = e.first,y = e.second;//x就是连接u的一条边,y就是权值
		if(!st[x])
		{
			dfs(x);
		 } 
		
	}
}
int main()
{
	int n,m; cin >> n >> m;
	for(int i = 1;i<=m;i++)
	{
		int a,b,c;
		cin >> a >> b >> c;
		ret[a].push_back({b,c});
		ret[b].push_back({a,c});
		
	}

	
	
	
	
	return 0;
}

链式前向星的dfs

#include <iostream>
#include <vector>
using namespace std;
const int N = 1010;
int n,m;
bool st[N];
int h[N],e[2*N],ne[2*N],w[N*2],id;
void add(int a,int b,int c) //把b结点头插到a结点后面的链表里
{
	id++;
	e[id] = b;
	ne[id] = h[a];
	h[a]=id;
	w[id] = c;
	
 } 
 void dfs(int u)
 {
 	 cout << u << " ";
 	 st[u] = true;
 	 for(int v = h[u];v;v=ne[v])
     {
     	 int x = e[v];
     	 if(!st[x])
     	 {
     	 	dfs(x);
		  }
	 }
 }
int main()
{
	int n,m;cin >> n >> m;//结点个数和边的个数 
	
	for(int i = 1;i<=m;i++)
	{
		int a,b,c;cin >> a >> b >> c;//ab表示两个结点
		add(a,b,c);//把b头插到a的结点里面  
		add(b,a,c);//把a头插到b的结点里面 
	}	
	
	
	
	
	
	
	return 0;
}

相关文章:

  • Matlab 基于SVPWM的VF三电平逆变器异步电机速度控制
  • 【Agent】OpenManus-Agent架构详细分析
  • 0-1背包问题 之 分割等和子集以及变形问题
  • 嵌入式SDIO 总线面试题及参考答案
  • 验证与调参——交叉验证/ 网格搜索/贝叶斯优化/随机搜索
  • 第7章 站在对象模型的尖端3: RTTI
  • Skema:AI 驱动的方案到 BIM 加速工具,重塑早期设计工作流
  • 堆排序:力扣215.数组中的第K个大元素
  • 自画flink、spark源码学习流程大图分享
  • 【商城实战(36)】UniApp性能飞升秘籍:从渲染到编译的深度优化
  • 【JavaEE】IOC和DI
  • 一周热点:Compact Reasoning 精简推理
  • 实体多ID关联分页查询实例
  • Compose笔记(十一)--DataStore(二)
  • Day09 -实例:拿到加密密文进行解密
  • 【拒绝算法PUA】LeetCode 2270. 分割数组的方案数
  • Dijkstra解决单源最短路径
  • 2.1 transformer模型原理及代码(python)
  • 深度学习常用操作笔记
  • 多重背包讲解
  • 著名蒙古族音乐学者马•斯尔古愣逝世,享年86岁
  • 巴基斯坦全面恢复领空开放
  • 祝贺!苏翊鸣成功解锁“2160”
  • 重庆大学通报本科生发14篇SCI论文:涉事学生及其父亲被处理
  • 五粮液董事长:茅台1935已脱离千元价位带,五粮液在千元价位已逐步摆脱其他竞品纠缠
  • 深圳两家会所涉卖淫嫖娼各被罚7万元逾期未缴,警方发催告书