【高阶数据结构(二)】初识图论

news2024/11/18 12:24:12

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:高阶数据结构专栏⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习更多Go语言知识
  🔝🔝


在这里插入图片描述

高阶数据结构

  • 1. 前言
  • 2. 图的基本概念
  • 3. 关于图的专业名词
  • 4. 图的存储结构
    • 4.1 邻接矩阵
    • 4.2 邻接表
    • 4.3 优缺点分析
  • 5. 图的模拟实现
  • 6. 总结以及拓展

1. 前言

相信在大学中学过离散数学这门课的同学一定对图比较熟悉. 为了照顾没有学习过图的同学,本系列文章会当作无基础来讲解

本章重点:

本篇文章着重讲解图的基本概念,关于图的一些专业名词,以及图的两个存储结构: 邻接矩阵和邻接表. 期间会带大家模拟实现邻接矩阵版本的图


2. 图的基本概念

图是由顶点集合,以及边集合组成的一种数据结构: G = (V,E).

在这里插入图片描述

概念很抽象,可以简化为下图:

在这里插入图片描述

G1中的顶点就是结点0,1,2,3.记作v1,v2…,两个顶点vi和vj相关联称作顶点vi和顶点vj之间有一条边,图中的第k条边记作ek,ek = (vi,vj)或<vi,vj>. 再看G2,这不是一颗二叉树吗?是的,可以将二叉想象为图的一种表现形式. 除此之外, 图还分为有向图和无向图, 有向图代表顶点之间的边是有方向的, 无向图代表边是无方向的,如下图所示:

在这里插入图片描述


3. 关于图的专业名词

  • 完全图: 在有n个顶点的无向图中,若有n * (n-1)/2条边,即任意两个顶点之间有且仅有一条边,则称此图为无向完全图. 上图的G1就是无向完全图, G4为有向完全图
  • 邻接顶点: 若顶点u和v有直接的边相连, 那么它们这两个顶点就称为邻接顶点
  • 顶点的度: 顶点v的度是它相关联的边的条数,记作deg(v)。在有向图中,顶点的度等于该顶点的入度与出度之和,其中顶点v的入度是以v为终点的有向边的条数,记作indev(v);顶点v的出度是以v为起始点的有向边的条数,记作outdev(v)。因此:dev(v) = indev(v) + outdev(v)。注意:对于无向图,顶点的度等于该顶点的入度和出度,即dev(v) = indev(v) = outdev(v)。

在这里插入图片描述

  • 路径: 若顶点A可以到达顶点B, 则从A到B经过的所有顶点就是A到B的路径. 对于不带权图,路径长度等于边数之和,带权图则是权值之和

在这里插入图片描述

  • 简单路径与回路: 一条路径中如果没有重复的点,那么就是简单路径,有重复的点证明有回路
  • 连通图: 连通图:在无向图中,若从顶点v1到顶点v2有路径,则称顶点v1与顶点v2是连通的。如果图中任意一对顶点都是连通的,则称此图为连通图

在这里插入图片描述

这些概念很多,很杂,不用全部背下来, 有个印象,后面使用时不至于听不懂就好了.可以联想到, 微信,QQ等社交平台一定是无向图,因为我是你好友的同时你必须也得是我好友.像抖音,快手,微博这种弱社交平台, 用的是有向图, 因为我关注了一个博主并不代表这个博主也要关注我


4. 图的存储结构

因为图中既有节点,又有边(节点与节点之间的关系),因此,在图的存储中,只需要保存:节点和边关系即可。节点保存比较简单,只需要一个数组存储即可,那边关系该怎么保存呢?

图的存储结构分为:

  1. 邻接矩阵
  2. 邻接表

4.1 邻接矩阵

因为节点与节点之间的关系就是连通与否,即为0或者1,因此邻接矩阵(二维数组)即是:先用一个数组将定点保存,然后采用矩阵来表示节点与节点之间的关系. 如一个图有n个顶点, 那么就开辟一个n×n的二维数组. 数组下标(i,j)位置存储的值代表,顶点i到j是否有边,用0/1表示.

在这里插入图片描述

对于无向图而言, 邻接矩阵是对称的,因为我有边到你的同时,你也一定有边到我. 但是对于有向图而言,就不是这么简单了,下面来看看

在这里插入图片描述

如果边带有权值,并且两个节点之间是连通的,上图中的边的关系就用权值代替,如果两个顶点不通,则使用无穷大代替

在这里插入图片描述


4.2 邻接表

邻接表: 用数组表示顶点的集合,用链表表示边的关系

无向图邻接表存储:

在这里插入图片描述

A,B,C,D的下标分别是0,1,2,3.所以A顶点有两个相邻的顶点B和C. 链表中存的就是1,2

有向图邻接表存储:

在这里插入图片描述


4.3 优缺点分析

用邻接矩阵存储图的有点是能够快速知道两个顶点是否连通,缺陷是如果顶点比较多,边比较少时,矩阵中存储了大量的0成为系数矩阵,比较浪费空间,并且要求两个节点之间的路径不是很好求。

而邻接表的优点是很快能判断出一个顶点与哪些顶点直接相连. 而邻接表想要知道两个顶点是否连通,要比邻接矩阵要麻烦


5. 图的模拟实现

首先, 使用邻接矩阵版本的图, 需要一个一维数组来存储顶点的集合, 需要一个二维数组来存储边的集合. 除此之外, 由于我们全程使用的是顶点的下标, 所以还需要一个map来存储顶点下标和顶点的值的对应关系.

框架代码:

template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
class Graph
{
public:
	//图的创建方法: 1. IO输入(不方便测试) 2. 样例写在文件中,读取文件 3. 手动添加边
	Graph(const V* a,size_t n)
	{
		_vertex.reserve(n);
		for (int i = 0; i < n; i++)
		{
			_vertex.push_back(a[i]);
			_index[a[i]] = i;
		}
		_edge.resize(n);
		for (int i = 0; i < n; i++)
			_edge[i].resize(n, MAX_W);
	}
private:
	vector<V> _vertex; //图的顶点集合
	vector<vector<W>> _edge;//图的边的集合
	unordered_map<V, int> _index;//存储顶点和它映射到vector的下标的关系
};

代码中的模板参数V代表顶点的类型,W代表边的类型(可能是整数,bool甚至是字符串),而MAX_W将作为边集合,二维数组的初始值. 最后一个代表,是否为有向图. 除此之外,图中还应该实现几个基本的函数: 添加边, 打印图的内容

完整的代码:

//邻接矩阵版本
template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
class Graph
{
public:
	//图的创建方法: 1. IO输入(不方便测试) 2. 样例写在文件中,读取文件 3. 手动添加边
	Graph(const V* a,size_t n)
	{
		_vertex.reserve(n);
		for (int i = 0; i < n; i++)
		{
			_vertex.push_back(a[i]);
			_index[a[i]] = i;
		}
		_edge.resize(n);
		for (int i = 0; i < n; i++)
			_edge[i].resize(n, MAX_W);
	}
	//找到顶点对应的下标
	size_t GetIndex(const V& v)
	{
		if (_index.find(v) == _index.end())
		{
			cout << "要添加的边的顶点不存在" << endl;
			return -1;
		}
		return _index[v];
	}
	void AddEdge(const V& src, const V& dest, const W& w)//向图中添加边(源点,目标点,以及权值)
	{
		size_t srci = GetIndex(src);
		size_t desti = GetIndex(dest);
		_edge[srci][desti] = w;
		if (Direction == false)
			_edge[desti][srci] = w;
	}
	void Print()
	{
		//打印顶点
		for (int i = 0; i < _edge[0].size(); i++)
			cout << "[" << i << "]" << "->" << _vertex[i] << endl;
		cout << endl;
		//打印矩阵
		for (int i = 0; i < _edge[0].size(); i++)
		{
			for (int j = 0; j < _edge[0].size(); j++)
			{
				if (_edge[i][j] == MAX_W)
					cout << "* ";
				else cout << _edge[i][j] << " ";
			}
			cout << endl;
		}
		cout << endl;
	}
private:
	vector<V> _vertex; //图的顶点集合
	vector<vector<W>> _edge;//图的边的集合
	unordered_map<V, int> _index;//存储顶点和它映射到vector的下标的关系
};

void TestGraph()
{
	Graph<char, int, -1, true> g("0123", 4);
	g.AddEdge('0', '1', 1);
	g.AddEdge('0', '3', 4);
	g.AddEdge('1', '3', 2);
	g.AddEdge('1', '2', 9);
	g.AddEdge('2', '3', 8);
	g.AddEdge('2', '1', 5);
	g.AddEdge('2', '0', 3);
	g.AddEdge('3', '2', 6);
	g.Print();
}

6. 总结以及拓展

其实模拟实现图的意义并不是简单的实现添加边的函数. 而是为了后面关于图的各种算法做铺垫. 图的学习难度会越来越大, 加油吧, 少年.


🔎 下期预告:图的遍历以及最小生成树 🔍

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

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

相关文章

vector、heap数组、stack数组访问性能验证

测试目的 本次测试旨在比较不同数据结构&#xff08;vector、数组&#xff09;以及不同访问方法&#xff08;[]、at()、offset&#xff09;在性能上的差异&#xff0c;从而为开发者提供在特定情境下做出最佳选择的依据。 测试代码 测试网址:Quick C Benchmarks 使用GCC9.5 …

基于YOLO的车牌与车型识别系统

一、项目背景与意义 随着智能交通系统的快速发展&#xff0c;车辆识别技术在交通管理、安防监控、自动收费、停车管理等领域发挥着至关重要的作用。车牌识别和车型识别作为车辆识别技术的核心组成部分&#xff0c;能够有效提升交通运营效率&#xff0c;加强公共安全监控&#…

Baidu Comate智能编码助手:引领编码新时代的智能伙伴

前言 在数字化高速发展的今天&#xff0c;编程技术已成为推动创新与技术革新的核心动力。伴随着软件项目的复杂性和规模不断扩大&#xff0c;编码过程中的挑战也日益增加。为了解决这些问题以达到降本增效的目的&#xff0c;百度推出了基于文心大模型的Baidu Comate智能编码助…

语义分割——前列腺分割数据集

引言 亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 …

SQL统计语句记录

1.达梦数据库 统计指定单位的12个月份的业务数据 SELECT a.DEPT_ID, b.dept_name, a.USER_NAME, count(a.dept_id) as count, sum(case when to_char(a.CREATE_TIME,yyyy-mm) 2023-01 THEN 1 else 0 end) as one,sum(case when to_char(a.CREATE_TIME,yyyy-mm) 2023-02 T…

【前端热门框架【vue框架】】——对组件进行更加简洁合理的处理和解释(一)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;程序员-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

量化交易T0策略:非凸T0算法

T0策略又称日内交易策略&#xff0c;它的持仓时间较短&#xff0c;基于对未来短期股价走势的判断&#xff0c;通过低位买入、高位卖出的方式来获得价差收益&#xff0c;并且买入卖出交易在日内完成。 分类 策略逻辑分类(融券T0和底仓T0) 融券T0在券商创立两融账号&#xff0c…

# 从浅入深 学习 SpringCloud 微服务架构(八)Sentinel(2)

从浅入深 学习 SpringCloud 微服务架构&#xff08;八&#xff09;Sentinel&#xff08;2&#xff09; 一、sentinel&#xff1a;通用资源保护 1、Rest 实现熔断 Spring Cloud Alibaba Sentinel 支持对 RestTemplate 的服务调用使用 Sentinel 进行保护, 在构造 RestTemplate…

Lazada商品详情API接口:深度解析与应用

前言 在当今电子商务的繁荣时代&#xff0c;对于电商平台来说&#xff0c;提供一套高效、稳定的API接口是非常重要的。Lazada&#xff0c;作为东南亚领先的电商平台之一&#xff0c;其API接口体系为卖家、开发者以及第三方服务提供了丰富的功能和数据支持。其中&#xff0c;商品…

多线程学习Day09

10.Tomcat线程池 LimitLatch 用来限流&#xff0c;可以控制最大连接个数&#xff0c;类似 J.U.C 中的 Semaphore 后面再讲 Acceptor 只负责【接收新的 socket 连接】 Poller 只负责监听 socket channel 是否有【可读的 I/O 事件】 一旦可读&#xff0c;封装一个任务对象&#x…

保姆级零基础微调大模型(LLaMa-Factory,多卡版)

此处非常感谢https://github.com/hiyouga/LLaMA-Factory这个项目。 看到网上的教程很多都是教如何用webui来微调的,这里出一期命令行多卡微调教程~ 1. 模型准备 模型下载比较方便的方法: 1. modelscope社区(首选,速度很高,并且很多需要申请的模型都有)注意要选择代码…

Redis快速学习

Redis快速学习 一、 Redis快速入门1.1 初始Redis1.1.1 Redis的存储方式1.1.2 NoSQL 与 sql 之间的区别 1.2 Redis概述1.2.1 Redis是什么1.2.2 Redis有什么用1.2.3 Redis的特性 1.3 Redis安装测试1.3.1 Redis Linux安装 1.4 Redis测试工具1.5 Redis的基本知识 二、Redis的五大数…

【Elasticsearch运维系列】Elasticsearch7.12.1启动指定版本JDK:你学废了吗?

一、背景 一套生ES集群&#xff0c;版本为7.12.1&#xff0c;近期频繁告警&#xff0c;频繁出现索引分片异常&#xff0c;索引状态异常&#xff0c;导致应用无法正常写入ES&#xff0c;另外&#xff0c;也经常出现节点掉问题。通过分析相关ES日志&#xff0c;显示和当前JAVA G…

C++ | Leetcode C++题解之第77题组合

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<int> temp;vector<vector<int>> ans;vector<vector<int>> combine(int n, int k) {// 初始化// 将 temp 中 [0, k - 1] 每个位置 i 设置为 i 1&#xff0c;即 [0, k - 1] 存…

细说夜莺监控系统告警自愈机制

虽说监控系统最侧重的功能是指标采集、存储、分析、告警&#xff0c;为了能够快速恢复故障&#xff0c;告警自愈机制也是需要重点投入建设的&#xff0c;所有可以固化为脚本的应急预案都可以使用告警自愈机制来快速驱动。夜莺开源项目从 v7 版本开始内置了告警自愈模块&#xf…

2024/5/9 英语每日一段

With runoff from this year’s snow and rain boosting the levels of California’s reservoirs, state water managers on Tuesday announced plans to increase deliveries of supplies from the State Water Project to 40% of full allotments, up from 30% last month. …

如何用opencv去掉单元格的边框线,以提高Tesseract识别率?

在OpenCV中处理从表格切割下来的图片&#xff0c;并去掉单元格的边框线&#xff0c;以提升Tesseract的识别准确率&#xff0c;确实是一个具有挑战性的任务。在这种情况下&#xff0c;我们需要采取一种策略来预处理图像&#xff0c;使得数字与背景之间的对比度增强&#xff0c;同…

聚观早报 | 苹果新款iPad Pro发布;国产特斯拉4月交付量

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 5月9日消息 苹果新款iPad Pro发布 国产特斯拉4月交付量 iOS 18新功能爆料 真我GT Neo6续航细节 三星Galaxy Z F…

楼宇自控远程I/O革新BACnet/IP模块在暖通空调系统

在现代智能建筑的浪潮中&#xff0c;BACnet/IP分布式远程I/O控制器正逐步成为暖通空调&#xff08;HAVC&#xff09;系统升级转型的得力助手。本文将以某大型商业综合体为例&#xff0c;揭示BACnet/IP I/O模块如何在复杂多变的环境中发挥其独特优势&#xff0c;实现HVAC系统的智…

Flink 算子

Flink 算子 用户通过算子能将一个或多个 DataStream 转换成新的 DataStream&#xff0c;在应用程序中可以将多个数据转换算子合并成一个复杂的数据流拓扑。 这部分内容将描述 Flink DataStream API 中基本的数据转换 API&#xff0c;数据转换后各种数据分区方式&#xff0c;以…