C++实现图的存储和遍历

news2024/11/15 6:55:48

前言

        许多新手友友在初学算法和数据结构时,会被图论支配过。我这里整理了一下图论常见的存储和遍历方式,仅供参考。如有问题,欢迎大佬们批评指正。

        存储我将提到四种方式:邻接矩阵、vector实现邻接表、数组模拟单链表实现的前向星实现邻接表、结构体数组直接存储边。遍历我将提到三种方式:dfs、bfs、按照边的权重值大小遍历输出。

一、邻接矩阵

#include <iostream>
#include <cstring>
#include <queue>
#include <functional>
constexpr int MAX_N = 1e3+5;
int g[MAX_N][MAX_N];
bool vis[MAX_N];
int main(){
	//取消同步流,加快输入输出 
	std::cin.tie(nullptr)->sync_with_stdio(false);
	
	//图的存储方式 1:邻接矩阵
	int n;std::cin >> n;
	for(int i = 1;i<=n;++i){
		for(int j = 1;j<=n;++j){
			std::cin >> g[i][j];
		}
	}
	
	//邻接矩阵的 dfs遍历
	memset(vis,false,sizeof vis);
	vis[1] = true;
	using Dfs = std::function<void(int)>;//目的是为了让 dfs函数可以进行递归 
	Dfs dfs = [&](int u)->void{//lambda表达式(函数) 
		std::cout << u << ' ';
		for(int i = 1;i<=n;++i){
			if(!vis[i]&&g[u][i]){
				vis[i]=true;
				dfs(i);
			}
		}
	};
	dfs(1);
	std::cout << '\n';
	
	//邻接矩阵的 bfs遍历
	auto bfs = [&]()->void{
		memset(vis,false,sizeof vis);
		std::queue<int> q;
		q.emplace(1);//emplace取代 push,可以加快运行速度 
		vis[1] = true;
		while(!q.empty()){
			auto t = q.front();
			q.pop();
			std::cout << t << ' ';
			for(int i = 1;i<=n;++i){
				if(!vis[i]&&g[t][i]){
					vis[i] = true;
					q.emplace(i);
				}
			}
		}
	};
	bfs();
	std::cout << '\n';
	
	return 0;
}

        测试

二、 vector实现邻接表

#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
#include <functional>
constexpr int MAX_N = 1e3+5,MAX_M = 1e6+5;
std::vector<std::pair<int,int>> edges[MAX_N];
bool vis[MAX_N];
int main(){
	std::cin.tie(nullptr)->sync_with_stdio(false);
	
	//图的存储方式 2:vector实现邻接表 
	int n,m;std::cin >> n >> m;
	while(m--){
		int x,y,w;std::cin >> x >> y >> w;
		//假设没有重边,无向边需要加两条边
		edges[x].emplace_back(y,w);
		edges[y].emplace_back(x,w);
	}
	
	//vector实现邻接表的 dfs遍历
	memset(vis,false,sizeof vis);
	vis[1] = true;
	using Dfs = std::function<void(int)>;
	Dfs dfs = [&](int u)->void{
		std::cout << u << ' ';
		for(int i = 0;i<edges[u].size();++i){
			if(!vis[edges[u][i].first]){
				vis[edges[u][i].first]=true;
				dfs(edges[u][i].first);
			}
		}
	};
	dfs(1);
	std::cout << '\n';
	
	//vector实现邻接表的 bfs遍历
	auto bfs = [&]()->void{
		memset(vis,false,sizeof vis);
		std::queue<int> q;
		q.emplace(1);
		vis[1] = true;
		while(!q.empty()){
			auto t = q.front();
			q.pop();
			std::cout << t << ' ';
			for(int i = 0;i<edges[t].size();++i){
				if(!vis[edges[t][i].first]){
					vis[edges[t][i].first] = true;
					q.emplace(edges[t][i].first);
				}
			}
		}
	};
	bfs();
	std::cout << '\n';
	
	return 0;
}

        测试

三、 数组模拟单链表实现的前向星实现邻接表

#include <iostream>
#include <cstring>
#include <queue>
#include <functional>
constexpr int MAX_N = 1e3+5,MAX_M = 1e6+5;
//h数组为头节点,值表示下一个节点的下标,值为 -1则表示指向 NULL(nullptr)
//有 idx到 e[idx]的边,权值为 w[idx],ne[idx]是 idx的下一个节点的下标 
int h[MAX_N],e[MAX_M],w[MAX_M],ne[MAX_M],idx;
bool vis[MAX_N];
int main(){
	std::cin.tie(nullptr)->sync_with_stdio(false);
	
	//图的存储方式 3:前向星实现邻接表
	//采用数组模拟单链表来实现前向星
	auto init = [&]()->void{
		memset(h,-1,sizeof h);//头结点初始值为 -1,表示 next指向 NULL(nullptr) 
		idx = 0;//下标从 0开始 
	};
	//注意这里是头插法,遍历的时候顺序是反的
	//但是大多数时候求最短路或者最小生成树不关注这个顺序 
	auto add = [&](int x,int y,int z)->void{
		//先勾右链,再勾左链
		e[idx]=y,w[idx]=z,ne[idx]=h[x],h[x]=idx++;
	};
	init();
	int n,m;std::cin >> n >> m;
	while(m--){
		int x,y,z;std::cin >> x >> y >> z;
		add(x,y,z),add(y,x,z);
	}
	
	//前向星实现邻接表的 dfs遍历
	memset(vis,false,sizeof vis);
	vis[1] = true;
	using Dfs = std::function<void(int)>;
	Dfs dfs = [&](int u)->void{
		std::cout << u << ' ';
		for(int i = h[u];~i;i=ne[i]){
			int j = e[i];
			if(!vis[j]){
				vis[j] = true;
				dfs(j);
			}
		} 
	};
	dfs(1);
	std::cout << '\n';
	
	//前向星实现邻接表的 bfs遍历
	auto bfs = [&]()->void{
		memset(vis,false,sizeof vis);
		std::queue<int> q;
		q.emplace(1);
		vis[1] = true;
		while(!q.empty()){
			auto t = q.front();
			q.pop();
			std::cout << t << ' ';
			for(int i = h[t];~i;i=ne[i]){
				int j = e[i];
				if(!vis[j]){
					vis[j] = true;
					q.emplace(j);
				}
			}
		}
	};
	bfs();
	std::cout << '\n';
	
	return 0;
}

        测试

四、 结构体数组直接存储边

#include <iostream>
#include <vector> 
#include <cstring>
#include <queue>
#include <algorithm>
#include <functional>
constexpr int MAX_N = 1e3+5,MAX_M = 1e6+5;
struct edge{
	int x,y,w;
	//重载 <符号,方便后续的sort()排序 
	bool operator < (const edge& W) {
		return w<W.w;
	}
	//写构造函数,方便后续直接 emplace_back
	edge(int _x,int _y,int _w):x(_x),y(_y),w(_w){}
};
std::vector<edge> edges;
std::vector<std::pair<int,int>> new_edges[MAX_N];
int h[MAX_N],e[MAX_M],w[MAX_M],ne[MAX_M],idx;
bool vis[MAX_N];
int main(){
	std::cin.tie(nullptr)->sync_with_stdio(false);
	
	//图的存储方式 4:结构体数组直接存储边
	int n,m;std::cin >> n >> m;
	while(m--){
		int x,y,w;std::cin >> x >> y >> w;
		edges.emplace_back(x,y,w);
	}
	
	//如果要实现 dfs和 bfs,只需把这种存边方式转换成第2或第3种即可
	//若要转换成第二种: 
	for(auto &t:edges){
		new_edges[t.x].emplace_back(t.y,t.w);
	}
	//若要转换成第三种:
	auto init = [&]()->void{
		memset(h,-1,sizeof h);
		idx = 0;
	};
	auto add = [&](int x,int y,int z)->void{
		e[idx]=y,w[idx]=z,ne[idx]=h[x],h[x]=idx++;
	};
	init();
	for(auto &t:edges){
		add(t.x,t.y,t.w),add(t.y,t.x,t.w);
	}
	//再使用任意一种方式进行 dfs或者 bfs遍历
	//这里以第三种存图方式为例,dfs遍历 
	memset(vis,false,sizeof vis);
	vis[1] = true;
	using Dfs = std::function<void(int)>;
	Dfs dfs = [&](int u)->void{
		std::cout << u << ' ';
		for(int i = h[u];~i;i=ne[i]){
			int j = e[i];
			if(!vis[j]){
				vis[j] = true;
				dfs(j);
			}
		} 
	};
	dfs(1);
	std::cout << '\n';
	
	//bfs遍历
	auto bfs = [&]()->void{
		memset(vis,false,sizeof vis);
		std::queue<int> q;
		q.emplace(1);
		vis[1] = true;
		while(!q.empty()){
			auto t = q.front();
			q.pop();
			std::cout << t << ' ';
			for(int i = h[t];~i;i=ne[i]){
				int j = e[i];
				if(!vis[j]){
					vis[j] = true;
					q.emplace(j);
				}
			}
		}
	};
	bfs();
	std::cout << '\n';
	
	//按照边的权重值大小遍历输出
	std::sort(edges.begin(),edges.end());
	for(auto &t:edges){
		std::cout << t.x << ' ' << t.y << ' ' << t.w << '\n';
	}
	
	return 0;
}

        测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1685682.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FFmpeg开发笔记(三十)解析H.264码流中的SPS帧和PPS帧

《FFmpeg开发实战&#xff1a;从零基础到短视频上线》一书的“2.1.1 音视频编码的发展历程”介绍了H.26x系列的视频编码标准&#xff0c;其中H.264至今仍在广泛使用&#xff0c;无论视频文件还是网络直播&#xff0c;H.264标准都占据着可观的市场份额。 之所以H.264取得了巨大…

完美解决原生小程序点击地图markers上的点获取不到对应的坐标信息

需求&#xff1a;地图上有多个markes点&#xff0c;点击每一个获取对应的数据&#xff0c;再根据当前的坐标信息去调用导航。 出现的问题&#xff1a;每次点击的时候获取不到对应的坐标信息&#xff0c;获取到的信息显然不是想要的 原因&#xff1a; 因为你的id不是number类型&…

线上虚拟纪念馆的便利与优势,全天候开放的数字化历史体验

一、搭建线上虚拟纪念馆的意义 在现代社会中&#xff0c;线上虚拟纪念馆越来越受到人们的关注和欢迎。传统纪念馆需要大量的物理空间和资源&#xff0c;而线上虚拟纪念馆则突破了这些限制&#xff0c;提供了更多的可能性和优势。首先&#xff0c;线上虚拟纪念馆能够更好地保存和…

【有手就行】使用你自己的声音做语音合成,CPU都能跑,亲测有效

此文介绍在百度飞桨上一个公开的案例&#xff0c;亲测有效。 厌倦了前篇一律的TTS音色了吗&#xff1f;打开短视频听来听去就是那几个声音&#xff0c;快来试试使用你自己的声音来做语音合成吧&#xff01;本教程非常简单&#xff0c;只需要你能够上传自己的音频数据就可以(建议…

Mac虚拟机工具 CrossOver 24.0.0 Beta3 Mac中文版

CrossOver是一款在Mac上运行Windows应用程序的软件&#xff0c;无需安装虚拟机或重启计算机&#xff0c;简化了操作过程&#xff0c;提高了工作效率&#xff0c;为用户带来便捷体验。前往Mac青桔下载&#xff0c;享受前所未有的便利和高效。摘要由作者通过智能技术生成 CrossOv…

JVM严镇涛版笔记【B站面试题】

前言 2023-06-19 18:49:33 出自B站 灰灰的Java面试 枫叶云链接&#xff1a;http://cloud.fynote.com/s/4976 JVM面试题大全 Lecturer &#xff1a;严镇涛 1.为什么需要JVM&#xff0c;不要JVM可以吗&#xff1f; 1.JVM可以帮助我们屏蔽底层的操作系统 一次编译&#xff0c…

当代人工智能三教父——深度学习三巨头

文章目录 引言 人物介绍 突出贡献 专业名词解释 引言 今天下午闲来无事翻阅了一下csdn首页的头条文章——《27 岁天才创始人 Joel Hellermark 分享了自己和“AI 教父” Geoffery Hinton 的最新采访》 感觉挺有意思&#xff0c;就从头到尾的看了一遍&#xff0c;里面有很多…

6.1 if语句

计算机语言和人类语言类似&#xff0c;人类语言是为了解决人与人之间交流的问题&#xff0c;而计算机语言是为了解决程序员与计算机之间交流的问题。程序员编写的程序就是计算机的控制指令&#xff0c;控制计算机的运行。借助于编译工具&#xff0c;可以将各种不同的编程语言的…

免费分享一套微信小程序旅游推荐(智慧旅游)系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序旅游推荐(智慧旅游)系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序旅游推荐(智慧旅游)系统(SpringBoot后端Vue管理端) Java毕业设计…

谷歌B端独立站建站推广,外贸建站训练营,傻瓜式教学

做外贸方法重要&#xff0c;工具更重要&#xff0c;而这些背后的规则和套路&#xff0c;身边的人往往不会告诉你&#xff0c;成功的人更不会教给你。本套课程主要内容包括&#xff1a;一套体系化的独立站建站方法&#xff0c;学会“高效学习”避免无效努力&#xff0c;拥有独立…

144.栈和队列:有效的括号(力扣)

题目描述 代码解决 class Solution { public:bool isValid(string s) {// 如果字符串长度为奇数&#xff0c;不可能是有效的括号字符串if(s.size() % 2 ! 0) return false;// 使用栈来存放括号stack<char> st;// 遍历字符串中的每一个字符for(int i 0; i < s.size();…

redis小知识

AOF与RDB的区别 AOF (Append Only File) 和 RDB (Redis Database) 都是Redis中的持久化机制&#xff0c;但有以下几点不同之处&#xff1a; 内容格式&#xff1a;AOF 以日志的形式记录所有写操作命令&#xff0c;而 RDB 则是在指定的时间间隔内对数据库进行快照&#xff0c;将数…

柏拉图式表征:人工智能深度网络模型是否趋于一致?

人工智能模型是否正在向现实的统一表征演进&#xff1f;柏拉图表征假说认为&#xff0c;人工智能模型正在趋同。 麻省理工学院最近的一篇论文引起了我的注意&#xff0c;因为它提出了一个令人印象深刻的观点&#xff1a;人工智能模型正在趋同&#xff0c;甚至跨越了不同的模态…

GeoScene产品学习视频收集

1、易智瑞运营的极思课堂https://www.geosceneonline.cn/learn/library 2、历年易智瑞技术公开课视频资料 链接&#xff1a;技术公开课-易智瑞信息技术有限公司&#xff0c;GIS/地理信息系统&#xff0c;空间分析-制图-位置智能-地图 3、一些关于GeoScene系列产品和技术操作的…

计算机-编程相关

在 Linux 中、一切都是文件、硬件设备是文件、管道是文件、网络套接字也是文件。 for https://juejin.cn/post/6844904103437582344 fork 进程的一些问题 fork 函数比较特殊、一次调用会返回两次。在父进程和子进程都会返回。 每个进程在内核中都是一个 taskstruct 结构、for…

微软MSBuild大会发布Copilot+PC:技术革新还是隐私噩梦?

微软在最近的MSBuild 2024大会上发布了全新的CopilotPC概念&#xff0c;这一技术结合了高通骁龙X Elite芯片&#xff0c;将人工智能与PC紧密结合。此次发布引起了广泛关注&#xff0c;不仅是因为其技术创新&#xff0c;还因为潜在的隐私问题。甚至连Elon Musk也对此表示担忧&am…

第197题|奇偶性的四则运算,你掌握了吗?|函数强化训练(四)|武忠祥老师每日一题 5月22日

解题思路&#xff1a;这道题如果我们会21号的题的话&#xff0c;简直是小菜一碟&#xff01;主要就是要用到下面这个结论&#xff1a; &#xff08;A&#xff09; 直接看奇偶性我们不好看&#xff0c;我们需要拆项&#xff1a; 我们先看前一项的奇偶性&#xff0c;x是奇函数&a…

自动化测试用例结构

标准的用例结构&#xff1a; 用力标题前提条件用例步骤预期结果实际结果 测试用例对比&#xff1a;

高稳定数显芯片防干扰抗噪数码屏驱动高亮LED驱动IC-VK16K33A/AA 最大13×3的按键扫描

产品型号&#xff1a;VK16K33A/AA 产品品牌&#xff1a;永嘉微电/VINKA 封装形式&#xff1a;SOP28/SSOP28 原厂&#xff0c;工程服务&#xff0c;技术支持&#xff01; 概述 VK16K33A/AA是一种带按键扫描接口的数码管或点阵LED驱动控制专用芯片&#xff0c;内部集成有数据…

MoonDream2微调指南【最小VLM】

在本指南中&#xff0c;我们将探讨如何使用计算机视觉数据集对完全开源的小型视觉语言模型 Moondream2 进行微调&#xff0c;以计数项目&#xff08;这是 GPT-4V 一直表现不一致的任务&#xff09;&#xff0c;并以一种可以依赖输出用于生产应用程序的方式进行微调。 视觉语言…