【高阶数据结构】秘法(二)——图(一):图的基本概念和存储结构

news2024/11/15 18:45:36

前言:

今天我们要讲解的是数据结构中图的部分,这部分在我们实际生活中也是经常会碰到的,同时这部分也是数据结构中比较有难度的部分,这部分内容我会把它分为多章来进行讲解,今天我们先来讲解一下图的基本概念和存储结构

目录

一、图的基本概念

1. 图的定义

2. 术语解释

3. 图的分类

二、图的表示

1.邻接矩阵

2. 邻接表

三、总结


一、图的基本概念

1. 图的定义

图是一种非线性的数据结构:G=(V,E),它由节点(也称为顶点)和连接这些节点的边组成。图可以用来表示现实世界中的各种关系,如社交网络、交通网络、电路网络等。

2. 术语解释

  • 顶点(Vertex):图中的基本元素,可以表示任何实体,如人、地点、事物等。顶点集合V={x|x属于某个数据对象集}是有穷非空集合
  • 边(Edge):连接两个顶点的线,表示顶点之间的关系。边的集合:E={(x,y)|x,y属于V}(无向图)或者E={<x,y>|x,y属于V&&Path(x,y)}是顶点间关系的有穷集合
  • 邻接(Adjacent):如果两个顶点通过一条边直接相连,则称这两个顶点是邻接的。
  • 度(Degree):对于无向图而言,一个顶点的度是指与该顶点相连的边的数量。但是对于有向图来说,一个顶点的度分为入度和出度,顶点的入度是以该顶点为终点的有向边的条数,出度则是以该顶点为起点的有向边的条数,顶点的度等于入度和出度之和
  • 路径(Path):顶点序列,其中每对连续的顶点都是邻接的。
  • 环(Cycle):路径中的第一个和最后一个顶点是同一个顶点的情况。
  • 连通图:对于任意两个顶点,都存在一条路径连接它们,即图中每一个顶点都不是单独存在的,它们都可以通过各种路径互相到达(如果有顶点单独存在,没有与其它任意顶点相连,则称这个顶点为一个孤岛)
  • 连通分量:一个图中的不连通部分。

3. 图的分类

  • 无向图(Undirected Graph):连接两个顶点的边没有方向,没有方向意味着两个顶点是互相连通的,这种常见的如朋友关系图:我是你的好友,同样你也是我的好友

  • 有向图(Directed Graph):边有方向,有方向意味着一个顶点可以到另一个顶点,但是反过来不行,这种关系常见的如网页链接图:我可以点击这个链接跳到一个图片,但是无法通过这个图片再跳回原来的界面。

  • 简单图(Simple Graph):没有重复的边和自环(顶点连接到自身的边)。

  • 多重图(Multigraph):允许有重复的边和自环。

  • 带权图(Weighted Graph):每条边上都有权重,一般是数字,可以表示距离、成本等。比如,我们在修从杭州到西安的高铁时,我们可以选择经过郑州,也可以选择经过武汉,这就产生了不同的路径,我们可以比较两个路径的开支来选择经过哪个城市,这就是权值

二、图的表示

图的表示有以下三种方法:

1.邻接矩阵

  • 邻接矩阵:使用二维数组来表示图,其中矩阵的元素表示顶点之间的连接情况,顶点之间的关系只有连通与不连通,所以我们可以用0和1来表示

注意:

1、无向图的邻接矩阵是对称的,但是有向图的邻接矩阵不一定对称

2、如果边上带权值,可以用权值来代替上面的0和1,相连通的顶点可以用权值来表示,不连通的可以用无穷来表示

3、邻接矩阵的有点是可以直观的看出两个顶点之间是否相连,但是当顶点过多、边过少的时候,就会存储大量的0,就会很不方便

代码实现:

#include<iostream>
#include<vector>
#include<string>
#include<map>
template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
class Graph
{
public:
	typedef Graph<V, W, MAX_W, Direction> Self;
	Graph() = default;
	Graph(const V* vertexs, size_t n)
	{
		_vertexs.reserve(n);
		for (size_t i = 0; i < n; ++i)
		{
			_vertexs.push_back(vertexs[i]);
			_vIndexMap[vertexs[i]] = i;
		}
		// MAX_W 作为不存在边的标识值
		_matrix.resize(n);
		for (auto& e : _matrix)
		{
			e.resize(n, MAX_W);
		}
	}
	size_t GetVertexIndex(const V& v)
	{
		auto ret = _vIndexMap.find(v);
		if (ret != _vIndexMap.end())
		{
			return ret->second;
		}
		else
		{
			throw invalid_argument("不存在的顶点");
			return -1;
		}
	}
	void _AddEdge(size_t srci, size_t dsti, const W& w)
	{
		_matrix[srci][dsti] = w;
		if (Direction == false)
		{
			_matrix[dsti][srci] = w;
		}
	}
	void AddEdge(const V& src, const V& dst, const W& w)
	{
		size_t srci = GetVertexIndex(src);
		size_t dsti = GetVertexIndex(dst);
		_AddEdge(srci, dsti, w);
	}

	void Print()
	{
		// 打印顶点和下标映射关系
		for (size_t i = 0; i < _vertexs.size(); ++i)
		{
			cout << _vertexs[i] << "-" << i << " ";
		}
		cout << endl << endl;
		cout << " ";
		for (size_t i = 0; i < _vertexs.size(); ++i)
		{
			cout << i << " ";
		}
		cout << endl;
		// 打印矩阵
		for (size_t i = 0; i < _matrix.size(); ++i)
		{
			cout << i << " ";
			for (size_t j = 0; j < _matrix[i].size(); ++j)
			{
				if (_matrix[i][j] != MAX_W)
					cout << _matrix[i][j] << " ";
				else
					cout << "#" << " ";
			}
			cout << endl;
		}
		cout << endl << endl;
		// 打印所有的边
		for (size_t i = 0; i < _matrix.size(); ++i)
		{
			for (size_t j = 0; j < _matrix[i].size(); ++j)
			{
				if (i < j && _matrix[i][j] != MAX_W)
				{
					cout << _vertexs[i] << "-" << _vertexs[j] << ":" <<
						_matrix[i][j] << endl;
				}
			}
		}
	}

private:
	map<V, size_t> _vIndexMap;
	vector<V> _vertexs; // 顶点集合
	vector<vector<W>> _matrix;  //存储边集合的矩阵
};
void TestGraph()
{
	Graph<char, int, INT_MAX, 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();
}
int main()
{
	TestGraph();
	return 0;
}

运行结果:

2. 邻接表

  • 邻接表:使用列表来表示图,每个顶点对应一个列表,列表中包含所有与该顶点相连的顶点。
  • template<class W>
    struct LinkEdge
    {
    	int _srcIndex;
    	int _dstIndex;
    	W _w;
    	LinkEdge<W>* _next;
    	LinkEdge(const W& w)
    		: _srcIndex(-1)
    		, _dstIndex(-1)
    		, _w(w)
    		, _next(nullptr)
    	{}
    };
    template<class V, class W, bool Direction = false>
    class Graph
    {
    	typedef LinkEdge<W> Edge;
    public:
    	Graph(const V* vertexs, size_t n)
    	{
    		_vertexs.reserve(n);
    		for (size_t i = 0; i < n; ++i)
    		{
    			_vertexs.push_back(vertexs[i]);
    			_vIndexMap[vertexs[i]] = i;
    		}
    		_linkTable.resize(n, nullptr);
    	}
    	size_t GetVertexIndex(const V& v)
    	{
    		auto ret = _vIndexMap.find(v);
    		if (ret != _vIndexMap.end())
    		{
    			return ret->second;
    		}
    		else
    		{
    			throw invalid_argument("不存在的顶点");
    			return -1;
    		}
    	}
    	void AddEdge(const V& src, const V& dst, const W& w)
    	{
    		size_t srcindex = GetVertexIndex(src);
    		size_t dstindex = GetVertexIndex(dst);
    		// 0 1
    		Edge* sd_edge = new Edge(w);
    		sd_edge->_srcIndex = srcindex;
    		sd_edge->_dstIndex = dstindex;
    		sd_edge->_next = _linkTable[srcindex];
    		_linkTable[srcindex] = sd_edge;
    		// 1 0
    		// 无向图
    		if (Direction == false)
    		{
    			Edge* ds_edge = new Edge(w);
    			ds_edge->_srcIndex = dstindex;
    			ds_edge->_dstIndex = srcindex;
    			ds_edge->_next = _linkTable[dstindex];
    			_linkTable[dstindex] = ds_edge;
    		}
    	}
    private:
    	map<string, int> _vIndexMap;
    	vector<V> _vertexs; // 顶点集合
    	vector<Edge*> _linkTable;   // 边的集合的临接表
    };
    void TestGraph()
    {
    	string a[] = { "张三", "李四", "王五", "赵六" };
    	Graph<string, int> g1(a, 4);
    	g1.AddEdge("张三", "李四", 100);
    	g1.AddEdge("张三", "王五", 200);
    	g1.AddEdge("王五", "赵六", 30);
    }
    

  • 边列表:使用列表来存储图中的所有边,每条边由两个顶点表示。(这个不常用,在这里不做过多解释,想要了解的可以自行搜索一下)

三、总结

这篇讲的还是图的基本内容,后面我们会讲解图的广度和深度遍历,以及与图有关的算法

感谢各位大佬观看,创作不易,还望各位大佬点赞支持!!!

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

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

相关文章

Codeforces Round 920 (Div. 3)(A,B,C,D)

A 在二维坐标轴上有一个正方形&#xff0c;给你一个正方形的四个顶点坐标&#xff0c;求面积 知道一个边长&#xff0c;平方即可 for(int i0;i<4;i)x[i]x1; Arrays.sort(x); //1122 kMath.abs(x[2]-x[1]); System.out.println(k*k); B 操作1、2是添加和修改&#xff0c;操…

Windows系统下的Spark环境配置

一&#xff1a;Spark的介绍 Apache Spark 是一个开源的分布式大数据处理引擎&#xff0c;它提供了一整套开发API&#xff0c;包括流计算和机器学习。Spark 支持批处理和流处理&#xff0c;其显著特点是能够在内存中进行迭代计算&#xff0c;从而加快数据处理速度。尽管 Spark …

【专题】2024年8月中国企业跨境、出海、国际化、全球化行业报告汇总PDF合集分享(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p37584 在全球化浪潮汹涌澎湃的当下&#xff0c;中国企业积极探索海外市场&#xff0c;开启了出海跨境的新征程。本报告合集旨在全面梳理出海跨境全球化行业的发展态势&#xff0c;涵盖多个领域的深度洞察。 从游戏、快消品、医疗器…

Python行结构(逻辑行、物理行、显式拼接行、隐式拼接行、空白行)

Python行结构 &#xff08;逻辑行、物理行、显式拼接行、隐式拼接行、空白行&#xff09; 本文目录&#xff1a; 零、时光宝盒 一、Python PEP8 编码行规范 1.1、Maximum Line Length 行的最大长度 1.2、在二元运算符之前应该换行吗&#xff1f; 二、Python行结构 2.1、物…

电子设计-基础3-电感与二极管

电子设计-基础3-电感与二极管 电感电感简介电感的发展历史电感的原理结构电感的性质&#xff1a; 电流惯性电感性质的演示 电感的分类常用的几种电感&#xff1a;一体成型电感一、定义与结构二、特点 三、工作原理四、应用领域 五、优缺点屏蔽电感 CD系列电感&#xff1a;多用于…

网站安全问题整改

网站安全、政务云、第三方安全检测机构等评测出来的网站web安全问题整改&#xff0c;如果你也正需要做这方面&#xff0c;请联系我吧

【代码随想录训练营第42期 Day50打卡 - dfs入门 - 卡码网 98. 所有可达路径

目录 一、dfs基础 二、模板题 题目&#xff1a;98. 所有可达路径 题目链接 题解&#xff1a;dfs邻接矩阵 三、小结 一、dfs基础 dfs是按照一个方向搜索到尽头再搜索其他方向。怎样实现对其他方向的搜索呢&#xff1f;我们可以通过回溯&#xff0c;撤销最后一步&#xff0c…

JUC-无锁之CAS

问题提出 (应用之互斥) package cn.itcast; import java.util.ArrayList; import java.util.List; interface Account {// 获取余额Integer getBalance();// 取款void withdraw(Integer amount);/*** 方法内会启动 1000 个线程&#xff0c;每个线程做 -10 元 的操作* 如果初始…

2024全国大学省数学建模竞赛C题-优秀论文分析(2023)

​某商超蔬菜类商品动态定价与补货决策研究 摘 要 随着生鲜市场规模的持续扩大&#xff0c;蔬菜零售行业的竞争也愈加激烈。为帮助某商超 改善经营模式&#xff0c;本文基于题目所给数据信息&#xff0c;建立数学模型进行分析&#xff0c;从而制定合理 的蔬菜类商品动态定价与…

ARM发布新一代高性能处理器N3

简介 就在2月21日&#xff0c;ARM发布了新一代面向服务器的高性能处理器N3和V3&#xff0c;N系列平衡性能和功耗&#xff0c;而V系列则注重更高的性能。此次发布的N3&#xff0c;单个die最高32核&#xff08;并加入到CCS&#xff0c;Compute Subsystems&#xff0c;包含Core&a…

C语言函数不同个数、大小形参对执行速度的影响:以Cortex-M3为例从汇编角度分析原因

0 资料&工具 Cortex M3权威指南(中文).pdf keil5&#xff08;用于仿真查看汇编代码、栈变化&#xff09;1 C语言函数不同个数、大小形参对执行速度的影响&#xff1a;以Cortex-M3为例从汇编角度分析原因 C语言中有条不成文的规定&#xff1a;不建议函数的形参数量超过4个…

C8T6超绝模块--LED

C8T6超绝模块–LED 大纲 怎样点亮LED结构体分析代码流程 具体案例 怎样点亮LED 首先不同的芯片的接法不一样&#xff0c;需要自己查看自己的芯片的原理图&#xff0c;我使用的是C8T6&#xff0c;使用的PC13接入的LED 注意看&#xff1a;怎么才能使LED灯亮呢&#xff1f; …

flux 文生图大模型 自有数据集 lora微调训练案例

参考: https://github.com/ostris/ai-toolkit 目前 Flux 出现了 3 个训练工具 SimpleTuner https://github.com/bghira/SimpleTuner X-LABS 的https://github.com/XLabs-AI/x-flux ai-toolkit https://github.com/ostris/ai-toolkit 待支持:https://github.com/kohya-ss/sd-s…

RK3588平台开发系列讲解(显示篇)MIPI详解

文章目录 一、DSI和CSI二、初识MIPI2.1、框架2.2、参数2.3、接口三、设备树下CSI的配置沉淀、分享、成长,让自己和他人都能有所收获!😄 一、DSI和CSI DSI( Display Serial Interface ) :位于处理器和显示模组之间的显示串行接口CSI( Camera Serial Interface ) : 位于…

Linux 安装nodejs环境

文章目录 Node.js简介Node.js的核心特性Node.js的生态系统Node.js的模块系统 部署下载Node.js预编译二进制包上传到Linux服务器并解压配置环境变量验证安装 部署在下边&#xff0c;我先对nodejs进行一些介绍&#xff0c;大家了解一下 Node.js简介 Node.js是一个基于Chrome V8…

计算机毕业设计Spark+PyTorch知识图谱房源推荐系统 房价预测系统 房源数据分析 房源可视化 房源大数据大屏 大数据毕业设计 机器学习

《SparkPyTorch知识图谱房源推荐系统》开题报告 一、选题背景与意义 1.1 选题背景 随着互联网的快速发展和大数据技术的广泛应用&#xff0c;房地产行业特别是房屋租赁市场迎来了前所未有的变革。房源信息的海量增长使得用户在寻找合适的房源时面临巨大挑战。传统的房源推荐…

集成电路学习:什么是IDE集成开发环境

IDE&#xff1a;集成开发环境 IDE&#xff0c;全称“Integrated Development Environment”&#xff0c;即集成开发环境&#xff0c;是一种用于提供程序开发环境的应用程序。它集成了代码编写、分析、编译、调试等多种功能于一体的开发软件服务套&#xff0c;为开发者提供了一个…

集成电路学习:什么是MPU微处理器

一、MPU&#xff1a;微处理器 MPU&#xff0c;全称Microprocessor Unit&#xff0c;即微处理器单元&#xff0c;是计算机系统中的核心部件之一。MPU是一种集成了中央处理器&#xff08;CPU&#xff09;、内存、外设控制器和总线接口等功能的芯片&#xff0c;为电子设备提供强大…

Linux驱动(五):Linux2.6驱动编写之设备树

目录 前言一、设备树是个啥&#xff1f;二、设备树编写语法规则1.文件类型2.设备树源文件&#xff08;DTS&#xff09;结构3.设备树源文件&#xff08;DTS&#xff09;解析 三、设备树API函数1.在内核中获取设备树节点&#xff08;三种&#xff09;2.获取设备树节点的属性 四、…

2024 World Conference of Computer and Information Security(WCCIS 2024)

文章目录 一、会议详情二、重要信息三、大会介绍四、出席嘉宾五、征稿主题六、咨询 一、会议详情 二、重要信息 大会官网&#xff1a;https://ais.cn/u/vEbMBz提交检索&#xff1a;EI Compendex、IEEE Xplore、Scopus截稿日期&#xff1a;2024年9月4日2024年9月27-29日 广西桂…