高阶数据结构[2]图的初相识

图的初相识

1.前言

2.图的概念

3.图的相关术语

4.图的存储结构 

4.1邻接矩阵 

4.2邻接表 

4.3两种存储方式的对比

 5.图的存储实现

5.1邻接矩阵的实现

5.2邻接表的实现 

6.总结 


1.前言

本章将大家学习数据结构中的“图”。有学习过离散数学的同学对这一章节或许会比较熟悉。本篇文章将从最基础的概念开始介绍,一步步深入。让我们开始吧!

2.图的概念

大家是否还记得我们学过的“树”?“树”就是一种无环的连通图。

图有两个部分组成:1.顶点集合  2.顶点间形成的边。

因此图是一种由顶点集合以及边集合组成的一种数据结构表示为G=(V,E)。

下面我们用图像来理解该概念。

如上图所示。G1中四个顶点0,1,2,3 ,各顶点形成连接的边。抽象概念可以表示为顶点集合v1,v2,v3,v4。形成的边可以表示为ek=(vi,vj),表示改边由顶点vi和vj连接而成。

G2就是我们刚刚介绍的树是一种无向连通图。

 既然说到了无向图,那么必然就有有向图。如图,G3,G4均为有向图。相信大家能看出来有向图和无向图的区别了!无向图没有明确的指向,而有向图则有明确的指向。

3.图的相关术语

在图的学习中,会涉及到大量的专业名词,我们在此一一列举。

\bigstar完全图:在有n个顶点的无向图中,若有n * (n-1)/2条边,即任意两个顶点之间有且仅有一条边,则称此图为无向完全图. 上图的G1就是无向完全图, G4为有向完全图。


\bigstar邻接顶点: 若顶点u和v有直接的边相连, 那么它们这两个顶点就称为邻接顶点。


\bigstar顶点的度: 顶点v的度是它相关联的边的条数,记作deg(v)。在有向图中,顶点的度等于该顶点的入度与出度之和,其中顶点v的入度是以v为终点的有向边的条数,记作indev(v);顶点v的出度是以v为起始点的有向边的条数,记作outdev(v)。因此:dev(v) = indev(v) + outdev(v)。注意:对于无向图,顶点的度等于该顶点的入度和出度,即dev(v) = indev(v) = outdev(v)。如上图中的G1每个顶点的度都为2。

上图中的G3中顶点1的出度为2,入度为1,顶点的度为3.


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


 \bigstar简单路径和回路:从图上的任一顶点出发,路径上经过的顶点只过一次,则为简单路径。

回路则是路径的上的出发点和结束点为同一个顶点形成一个环。如图。


 \bigstar子图:图2的顶点和边都是图1的一部分 ,则称图2是图1的子图。如图。


 \bigstar连通图:在无向图中,若两顶点间有边则称这两个边连通。若任意两个顶点都有边,则称为连通图。


\bigstar强连通图:在有向图中,任意两个顶点间都有相连的边,并且顶点1有指向顶点2,顶点2也指向1。


\bigstar生成树:一个无向连通图的最小连通子图称为改图的生成树。n个顶点的连通图的生成树有n-1条边。

4.图的存储结构 

图的存储结构有两种:1.邻接矩阵 2.邻接表

4.1邻接矩阵 

 邻接矩阵用以判断顶点间是否连通,用0来表示连通,1来表示不连通。

因此,我们用二维数组来实现邻接矩阵,表示两点是否连接。

 如上图,对于无向图,矩阵是对称的。因为,A对于B是连通的,B对于A也是连通的。

对于有向图而言,如图,二维数组的行表示边是由该顶点出发,而列则为被指向的顶点。

若图中的边带有权值,则在二维矩阵中用无穷大来表示两顶点间无边即不连通。

4.2邻接表 

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

无向图的邻接表

 假设顶点A,B,C,D 的下标为0,1,2,3。与A连通的有B,C。所以在邻接表中,A指向B,C。

有向图的邻接矩阵 

有向图的邻接表中包含有入边表和出边表。以A为例,顶点E指向A因此在入边表中A连接E的下标4。在出边表中,由于从A出的边指向B和D,所以出边表指向B和D的下标1,3。 

 4.3两种存储方式的对比

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

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

 5.图的存储实现

 首先,和学习其他数据结构一样。我们先来实现图的基本框架。上代码。

template<class V,class W,W MAX_W=INT_MAX,bool Direction=false>//V表示顶点的类型 W表示边的类型,MAX_W作为二维数组的初始值
class Graph {
piblic:Graph(const V* a, size_t n){_vertrx.resize(n);//为顶点集合开辟空间for (int i = 0; i < n; i++){_vertex.push(a[i]);//将数组中的值写入集合_indexMap[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;//存储边的集合map<v, w>_indexMap;//存储顶点和其映射
};

5.1邻接矩阵的实现

	namespace martix {template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>class Graph {public:Graph(const V* a, size_t n){_vertex.reserve(n);for (int i = 0; i < n; i++){_vertex.push_back(a[i]);_indeMap[a[i]] = i;}_edge.resize(n, MAX_W);}size_t GetIndex(const V& v){if (_indexMap.find(v) == _index.end())//map的特性,找不到时就等于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.size(); i++)cout << "[" << i << "]" << "->" << _vertex[i] << endl;cout << endl;//打印矩阵for (int i = 0; i < _edge.size(); i++)//横坐标{for (int j = 0; i < _edge[i]).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;//边的集合map<v, w>_indexMap;}

5.2邻接表的实现 

	namespace link_table{template<class W>//边的权值struct Edge {int _dsti;//目标点的下标W _w;Edge<W>* _next;Edge(int dsti, constW& w)//邻接表用链表的形式实现,因此是对每一个结点进行初始化:_dsti(dsti), _w(W), _next(nullptr){}};template<class V, class W, bool Direction = false>class Graph {typedef Edge<W> Edge;public:Graph(const V* a, size_t n){_vertex.reverse(n);//顶点集合开辟空间for (int i = 0; i < n; i++){_vertex.push_back(a[i]);_indexMap(a[i]) = i;}_tables.resize(m, nullptr);}size_t GetVertexIndex(const V& v){size_t it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;//返回顶点集合映射的下标}else {return -1;}}void AddEdge(const V& src, const V& dst, const W& w){size_t srci = GetVertexIndex(src);sizet_t dsti = GetVertexIndex(dst);Edge* eg = new Edge(dsti, w);//对结点进行开辟eg->_next = _tables[srci];//头插的方式加入邻接表的新边,指向原来的头_tables[srci] = eg;//做新头if (Direction == false){Edge* eg = new Edge(srci, w);eg->_next;_tables[dsti];_tables[dsti] = edge;//做新头}}void Print(){for (size_t i = 0; i < _vertex.size(); i++){cout << "[" << i << "]" << "->" << _vertex[i] << endl;//下标对应的顶点}cout << endl;for (size_t i = 0; i < _tables.size(); i++){cout << _vertex[i] << "[" << i << "]" << "->";Edge* cur = _tables[i];while (cur)//和链表一样的遍历方式{cout << "[" << _vertexs[cur->_dsti] << ":" << cur->_dsti << ":" << cur->_w << "]->";cur = cur->_next;}}}private:vector<V>_vertex;//顶点的集合map<V, int>_indexMap;vector<Edge*>_tables;};}

可以看到,邻接矩阵和邻接表在实现时的差别,邻接矩阵使用二维数组,而邻接表则使用的链表。

此外,在邻接表中插入新边时,我们使用的是头插的方式,因为这样可以免去找链表尾的操作。 

6.总结 

本篇文章,我们对图进行了基本的了解。在后续讲解图的相关算法时,我们将以邻接矩阵的存储方式的基本框架来分析。

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

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

相关文章

【归并排序】| 详解归并排序核心代码之合并两个有序数组 力扣88

&#x1f397;️ 主页&#xff1a;小夜时雨 &#x1f397;️专栏&#xff1a;动态规划 &#x1f397;️如何活着&#xff0c;是我找寻的方向 目录 1. 题目解析2. 代码 1. 题目解析 题目链接: https://leetcode.cn/problems/merge-sorted-array/description/ 本道题是归并排序的…

超拟人大模型:AI心理健康服务的未来

摘要&#xff1a; 周末听了一场聆心智能关于情感LLM的分享&#xff0c;总结了相关内容如下。在人工智能技术的浪潮中&#xff0c;超拟人大模型技术为心理健康服务领域带来了革命性的变化。本文将分析超拟人大模型的进展、CharacterGLM模型的特点、Emohaa模型的应用以及心理健康…

AI 挑战周杰伦?Suno 全新功能面世,即兴哼几句就能创作成歌,还能模仿声音!...

作者 | 王启隆 出品丨AI 科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09; 2016 年&#xff0c;周杰伦根据女儿 Hathaway 在玩具钢琴上随意弹出的几个音符&#xff0c;激发出创作的灵感&#xff0c;谱写了一首温馨而深情的歌曲——《前世情人》。8 年过去&#xff0…

【每日随笔】摩托车控车 ① ( 油离配合 | 落脚油离配合 - 不给油 | 落脚油离配合 - 给油 | 正式油离配合 | 骑行姿态注意事项 )

文章目录 一、找 " 离合结合点 "二、落脚油离配合 ( 不给油 )1、该科目练习目的2、起步姿态3、开始练习 三、落脚油离配合 ( 给油 )1、练习目的2、熟悉油门转速3、练习步骤 四、正式油离配合1、练习目的2、练习步骤3、练习效果 五、骑行姿态注意事项1、基本骑行姿态2…

Cisco Packet Tracer实验(四)

生成树协议&#xff08;Spanning Tree Protocol&#xff09; 交换机在目的地址未知或接收到广播帧时是要进行广播的。如果交换机之间存在回路/环路&#xff0c;那么就会产生广播循环风暴&#xff0c;从而严重影响网络性能。 而交换机中运行的STP协议能避免交换机之间发生广播…

解决Qt的multimedia库在clion中依赖库补全的问题

解决Qt的multimedia库在clion中使用报错的问题 在clion中&#xff0c;使用Qt的multimedia库时会报如下错误&#xff1a; defaultServiceProvider::requestService(): no service found for - "org.qt-project.qt.mediaplayer" 我猜测出现这个错误的原因很可能是因为…

迅狐短视频矩阵管理系统核心功能

一、多平台管理&#xff1a;连接多个主流自媒体平台&#xff0c;满足多平台、多账号、多角色的协调需求 在现如今的多元化媒体环境中&#xff0c;一个优秀的内容创作者需要同时管理多个自媒体平台&#xff0c;并以不同的身份角色展现自己。迅狐短视频矩阵管理系统强大的多平台…

数据结构重要知识总结

数组 数组&#xff08;Array&#xff09; 是一种很常见的数据结构。它由相同类型的元素&#xff08;element&#xff09;组成&#xff0c;并且是使用一块连续的内存来存储。 我们直接可以利用元素的索引&#xff08;index&#xff09;可以计算出该元素对应的存储地址。 数组…

如何充分利用 Postgres 的内存设置

为了充分利用 PostgreSQL 的内存设置&#xff0c;你需要调整多个参数以优化数据库性能。这些参数包括共享缓冲区&#xff08;shared_buffers&#xff09;、工作内存&#xff08;work_mem&#xff09;、维护工作内存&#xff08;maintenance_work_mem&#xff09;、有效缓存大小…

仅凭一图,即刻定位,AI图像定位技术

AI图像定位技术&#xff0c;解锁空间密码&#xff01;仅凭一图&#xff0c;即刻定位&#xff0c;精准至经纬度坐标&#xff0c;让世界无处不晓。 试试看能否猜中这张自拍照的背景所在&#xff1f;可别低估了A的眼力&#xff0c;答案说不定会让你大吃一惊呢。 近期&#xff0c;…

JWT令牌、过滤器Filter、拦截器Interceptor

目录 JWT令牌 简介 JWT生成 解析JWT 登陆后下发令牌 过滤器(Filter) Filter快速入门 Filter拦截路径 过滤器链 登录校验Filter-流程 拦截器(Interceptor) Interceptor 快速入门 拦截路径 登录校验流程 JWT令牌 简介 全称:JSON Web Token(https://iwt.io/) …

React 中的事件处理

React 中是如何处理事件的&#xff0c;现在下面简单的一段代码&#xff1a; export default function App() {const AList lazy(()>import(./List.js))const r useRef(null) const [show, setShow] useState(false);return (<><button onFocus{()>{setShow…

【StructueEngineering】Wind Load Combination Patterns风荷载组合模式

文章目录 Combination PatternsBasic Rules of Combinations组合的基本规律Specific Combination Patterns1. First 8 Combinations (1 to 8)2. Middle 8 Combinations (9 to 16)3. Last 8 Combinations (17 to 24) Summary of CombinationsKey Variables and Parameters with …

Postgre 调优工具pgBadger部署

一&#xff0c;简介&#xff1a; pgBadger&#xff08;日志分析器&#xff09;类似于oracle的AWR报告&#xff08;基于1小时&#xff0c;一天&#xff0c;一周&#xff0c;一月的报告&#xff09;&#xff0c;以图形化的方式帮助DBA更方便的找到隐含问题。 pgbadger是为了提高…

轻松上手MYSQL:探索MySQL索引数据结构的奥秘-让数据库飞起来

​&#x1f308; 个人主页&#xff1a;danci_&#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL》&#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索MYSQL索引数据结构之旅✨ &#x1f44b; 大家好&#xff01;文本学习研…

代理IP协议有何区别?深入了解 SOCKS5、HTTP 代理

在数字通信领域&#xff0c;数据安全和匿名性都是非常重要的指标。互联网的不断发展催生了几种协议&#xff0c;每种协议都有独特的优势和挑战。其中&#xff0c;SOCKS5 代理、HTTP代理最为广泛使用&#xff0c;下面给大家一起讨论&#xff0c;HTTP代理与 SOCKS5代理&#xff0…

基于python深度学习的CNN图像识别鲜花-含数据集+pyqt界面

代码下载&#xff1a; https://download.csdn.net/download/qq_34904125/89383615 本代码是基于python pytorch环境安装的。 下载本代码后&#xff0c;有个requirement.txt文本&#xff0c;里面介绍了如何安装环境&#xff0c;环境需要自行配置。 或可直接参考下面博文进行…

Linux:基础IO(二.缓冲区、模拟一下缓冲区、详细讲解文件系统)

上次介绍了&#xff1a;Linux&#xff1a;基础IO&#xff08;一.C语言文件接口与系统调用、默认打开的文件流、详解文件描述符与dup2系统调用&#xff09; 文章目录 1.缓冲区1.1概念1.2作用与意义 2.语言级别的缓冲区2.1刷新策略2.2具体在哪里2.3支持格式化 3.自己来模拟一下缓…

FFMpeg解复用流程

文章目录 解复用流程图复用器与解复用器小结 解复用流程图 流程图&#xff0c;如上图所示。 复用器与解复用器 复用器&#xff0c;就是视频流&#xff0c;音频流&#xff0c;字幕流&#xff0c;其他成分&#xff0c;按照一定规则组合成视频文件&#xff0c;视频文件可以是mp4…