图【数据结构】

文章目录

  • 图的基本概念
  • 邻接矩阵
  • 邻接表
  • 图的遍历
    • BFS
    • DFS

图的基本概念

图是由顶点集合及顶点间的关系组成的一种数据结构
顶点和边:图中结点称为顶点

权值:边附带的数据信息

在这里插入图片描述

在这里插入图片描述
路径 : 在这里插入图片描述

简单路径 和 回路:在这里插入图片描述

子图:设图G = {V, E}和图G1 = {V1,E1},若V1属于V且E1属于E,则称G1是G的子图
在这里插入图片描述

连通图:在无向图中,若从顶点v1到顶点v2有路径,则称顶点v1与顶点v2是连通的。如果图中任意一对顶点都是连通的,则称此图为连通图

生成树:一个连通图的最小连通子图称作该图的生成树。有n个顶点的连通图的生成树有n个顶点和n-1条边

生成树就是用最少的边连通起来

最小生成树:构成生成树这些边加起来权值是最小的。

顶点的度:
**加粗样式**
在这里插入图片描述

邻接矩阵

在这里插入图片描述

#pragma once 
#include<map>
#include<vector>
#include<algorithm>
#include<assert.h>
#include<string>
#include <functional>
#include<iostream>
using namespace std;
//矩阵 
namespace matrix
{//V是顶点 ,W是 weight 权值 template <class V, class W, W MAX_W = INT_MAX, bool Direction = false>  //true是有向图 ,false是无向图class Graph{public://手动添加边Graph(const V* a, size_t n)  //用指针数组 存储顶点{_vertex.reserve(n);//初始化顶点和边for (size_t i = 0; i < n; i++){_vertex.push_back(a[i]);_indexMap[a[i]] = i; //通过顶点找下标}_matrix.resize(n);for (size_t i = 0; i < n; i++){//将邻接矩阵的权值设置为最大值_matrix[i].resize(n, MAX_W);}}size_t  GetVertexIndexMap(const V& v){auto  it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;}else //没有找到 {assert(false);return -1;}}void AddEdge(const V& src, const V& dst, const W& w){int srci = GetVertexIndexMap(src);int dsti = GetVertexIndexMap(dst);_matrix[srci][dsti] = w;//无向图 if (Direction == false){_matrix[srci][dsti] = w;_matrix[dsti][srci] = w;}}void  Print(){//顶点 for (int i = 0; i < _vertex.size(); i++){cout << "[" << i << "]" << "->" << _vertex[i] << endl;}//矩阵 cout << endl;//打印横下标cout << "  ";for (size_t i = 0; i < _vertex.size(); i++){cout << i << " ";}cout << endl;for (int i = 0; i < _matrix.size(); i++){cout << i << " ";//打印竖下标for (int j = 0; j < _matrix[0].size(); j++){if (_matrix[i][j] == MAX_W){cout << "*"<<" ";}else{cout << _matrix[i][j] <<" ";}}cout << endl;}}public:vector<V> _vertex;  //顶点集合 map<V, int>  _indexMap;					//顶点映射下标 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();}
}

邻接表

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

出边表:存储从各个顶点连接出去的边,出边表中下标为 i的位置存储的是从编号为i的顶点连接出去的边

入边表:存储连接到各个顶点的边,入边表中下标为i的位置存储的是连接到编号为 i的顶点的边
在这里插入图片描述
出边表和入边表的其中每个位置存储的都是一个链表
出边表中下标为i的位置表示从编号为i的顶点连接出去的边
入边表中下标为i 的位置表示连接到编号为i 的顶点的边

在实现邻接表时,一般只需要用一个出边表来存储从各个顶点连接出去的边即可,因为大多数情况下都是需要从一个顶点出发找与其相连的其他顶点,所以一般不需要存储入边表

//邻接表
namespace link_table
{template<class  W>struct Edge{int _dsti;//目标点的下标 W _w;//权值Edge<W> *_next; //用链表表示边的关系Edge(int dsti, const W& w):_dsti(dsti), _w(w), _next(nullptr)  {}};//V是顶点 ,W是 weight 权值 template <class V, class W, bool Direction = false>  //true是有向图 ,false是无向图class Graph{public:typedef Edge<W> Edge;//手动添加边Graph(const V* a, size_t n)  //用指针数组 存储顶点{_vertex.reserve(n);//初始化顶点和边for (size_t i = 0; i < n; i++){_vertex.push_back(a[i]);_indexMap[a[i]] = i; //通过顶点找下标}_table.resize(n, nullptr);}size_t  GetVertexIndexMap(const V& v){auto  it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;}else //没有找到 {assert(false);return -1;}}void AddEdge(const V& src, const V& dst, const W& w){int srci = GetVertexIndexMap(src); int dsti = GetVertexIndexMap(dst);//头插Edge *eg = new Edge(dsti,w);//有向图 //添加从源顶点到目标顶点的边eg->_next = _table[srci];_table[srci] = eg;//无向图 //添加从目标顶点到源顶点的边if (Direction == false){//????Edge* eg = new Edge(srci, w);eg->_next = _table[dsti];_table[dsti] = eg;}}void  Print(){//顶点 for (int i = 0; i < _vertex.size(); i++){cout << "[" << i << "]" << "->" << _vertex[i] << endl;}cout << endl;//遍历顶点for (size_t i = 0; i < _vertex.size(); i++){cout << _vertex[i] << endl;}//遍历邻接表的目标点的下标和权值 for (size_t i = 0; i < _table.size(); i++){cout << _vertex[i] << "[" << i << "]->";Edge * cur = _table[i];while (cur != nullptr){cout << "[" << _vertex[cur->_dsti] << ":" << cur->_dsti << ":" << cur->_w << "]->";cur = cur->_next;}cout << "nullptr" << endl;}}public:vector<V> _vertex;  //顶点集合 map<V, int>  _indexMap;					//顶点映射下标 vector<  Edge*>	 _table;					//邻接表};void TestGraph(){string a[] = { "张三", "李四", "王五", "赵六" };Graph<string, int, true> g1(a, 4);g1.AddEdge("张三", "李四", 100);g1.AddEdge("张三", "王五", 200);g1.AddEdge("王五", "赵六", 30);g1.Print();}
}

图的遍历

BFS

在这里插入图片描述

void BFS(const V& src)  //遍历顶点,通过下标找顶点{size_t srci = GetVertexIndexMap(src);queue<int>  q;vector<bool>  v(_vertex.size(), false);  //防止走重复的路q.push(srci);v[srci] = true;while (!q.empty()){int front = q.front();q.pop();cout << _vertex[front] << endl;// 把front顶点的邻接顶点的下标入队列for (size_t i = 0; i < _vertex.size(); i++){if (_matrix[front][i] != MAX_W && v[i] == false){q.push(i);v[i] = true;}}}}

DFS

在这里插入图片描述

void _DFS(    size_t srci  ,vector<bool> & v){cout << srci << ":" << _vertex[srci] << endl;v[srci] = true;// 找一个srci相邻的没有访问过的点,去往深度遍历for (int i =0 ; i< _vertex.size()  ; i++ ){if (v[i] ==false && _matrix[srci][i] != MAX_W){_DFS(i ,v);}}}void  DFS(const V& src) //遍历顶点,通过下标找顶点{vector<bool>  v(_vertex.size(), false);  //防止走重复的路size_t  srci = GetVertexIndexMap(src);_DFS(srci, v);}

完整测试代码

#pragma once 
#include<map>
#include<vector>
#include<algorithm>
#include<assert.h>
#include<string>
#include <functional>
#include<iostream>
#include<queue>
using namespace std;
//矩阵 
namespace matrix
{//V是顶点 ,W是 weight 权值 //连通的,边的关系就用权值代替,如果两顶点不通,则使用无穷大代替template <class V, class W, W MAX_W = INT_MAX, bool Direction = false>  //true是有向图 ,false是无向图class Graph{public://手动添加边Graph(const V* a, size_t n)  //用指针数组 存储顶点{_vertex.reserve(n);//初始化顶点和边for (size_t i = 0; i < n; i++){_vertex.push_back(a[i]);_indexMap[a[i]] = i; //通过顶点找下标}_matrix.resize(n);for (size_t i = 0; i < n; i++){//将邻接矩阵的权值设置为最大值_matrix[i].resize(n, MAX_W);}}size_t  GetVertexIndexMap(const V& v){auto  it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;}else //没有找到 {assert(false);return -1;}}void AddEdge(const V& src, const V& dst, const W& w){int srci = GetVertexIndexMap(src);int dsti = GetVertexIndexMap(dst);_matrix[srci][dsti] = w;//无向图 if (Direction == false){_matrix[srci][dsti] = w;_matrix[dsti][srci] = w;}}void  Print(){//顶点 for (int i = 0; i < _vertex.size(); i++){cout << "[" << i << "]" << "->" << _vertex[i] << endl;}//矩阵 cout << endl;//打印横下标cout << "  ";for (size_t i = 0; i < _vertex.size(); i++){cout << i << " ";}cout << endl;for (int i = 0; i < _matrix.size(); i++){cout << i << " ";//打印竖下标for (int j = 0; j < _matrix[0].size(); j++){if (_matrix[i][j] == MAX_W){cout << "*"<<" ";}else{cout << _matrix[i][j] <<" ";}}cout << endl;}}void BFS(const V& src)  //遍历顶点,通过下标找顶点{size_t srci = GetVertexIndexMap(src);queue<int>  q;vector<bool>  v(_vertex.size(), false);  //防止走重复的路q.push(srci);v[srci] = true;while (!q.empty()){int front = q.front();q.pop();cout << _vertex[front] << endl;// 把front顶点的邻接顶点的下标入队列for (size_t i = 0; i < _vertex.size(); i++){if (_matrix[front][i] != MAX_W && v[i] == false){q.push(i);v[i] = true;}}}}void _DFS(    size_t srci  ,vector<bool> & v){cout << srci << ":" << _vertex[srci] << endl;v[srci] = true;// 找一个srci相邻的没有访问过的点,去往深度遍历for (int i =0 ; i< _vertex.size()  ; i++ ){if (v[i] ==false && _matrix[srci][i] != MAX_W){_DFS(i ,v);}}}void  DFS(const V& src) //遍历顶点,通过下标找顶点{vector<bool>  v(_vertex.size(), false);  //防止走重复的路size_t  srci = GetVertexIndexMap(src);_DFS(srci, v);}public:vector<V> _vertex;  //顶点集合 map<V, int>  _indexMap;					//顶点映射下标 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();}void TestBDFS(){string a[] = { "张三", "李四", "王五", "赵六", "周七" };Graph<string, int> g1(a, sizeof(a) / sizeof(string));g1.AddEdge("张三", "李四", 100);g1.AddEdge("张三", "王五", 200);g1.AddEdge("王五", "赵六", 30);g1.AddEdge("王五", "周七", 30);g1.Print();//g1.BFS("张三");g1.DFS("张三");}
}//邻接表
namespace link_table
{template<class  W>struct Edge{int _dsti;//目标点的下标 W _w;//权值Edge<W> *_next; //用链表表示边的关系Edge(int dsti, const W& w):_dsti(dsti), _w(w), _next(nullptr)  {}};//V是顶点 ,W是 weight 权值 template <class V, class W, bool Direction = false>  //true是有向图 ,false是无向图class Graph{public:typedef Edge<W> Edge;//手动添加边Graph(const V* a, size_t n)  //用指针数组 存储顶点{_vertex.reserve(n);//初始化顶点和边for (size_t i = 0; i < n; i++){_vertex.push_back(a[i]);_indexMap[a[i]] = i; //通过顶点找下标}_table.resize(n, nullptr);}size_t  GetVertexIndexMap(const V& v){auto  it = _indexMap.find(v);if (it != _indexMap.end()){return it->second;}else //没有找到 {assert(false);return -1;}}void AddEdge(const V& src, const V& dst, const W& w){int srci = GetVertexIndexMap(src); int dsti = GetVertexIndexMap(dst);//头插Edge *eg = new Edge(dsti,w);//有向图 //添加从源顶点到目标顶点的边eg->_next = _table[srci];_table[srci] = eg;//无向图 //添加从目标顶点到源顶点的边if (Direction == false){//????Edge* eg = new Edge(srci, w);eg->_next = _table[dsti];_table[dsti] = eg;}}void  Print(){//顶点 for (int i = 0; i < _vertex.size(); i++){cout << "[" << i << "]" << "->" << _vertex[i] << endl;}cout << endl;//遍历顶点for (size_t i = 0; i < _vertex.size(); i++){cout << _vertex[i] << endl;}//遍历邻接表的目标点的下标和权值 for (size_t i = 0; i < _table.size(); i++){cout << _vertex[i] << "[" << i << "]->";Edge * cur = _table[i];while (cur != nullptr){cout << "[" << _vertex[cur->_dsti] << ":" << cur->_dsti << ":" << cur->_w << "]->";cur = cur->_next;}cout << "nullptr" << endl;}}public:vector<V> _vertex;  //顶点集合 map<V, int>  _indexMap;					//顶点映射下标 vector<  Edge*>	 _table;					//邻接表};void TestGraph(){string a[] = { "张三", "李四", "王五", "赵六" };Graph<string, int, true> g1(a, 4);g1.AddEdge("张三", "李四", 100);g1.AddEdge("张三", "王五", 200);g1.AddEdge("王五", "赵六", 30);g1.Print();}
}

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

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

相关文章

MySQL8 设置大小写敏感

问题描述 今天对我本地的数据库迁移服务器上&#xff0c;完成之后启动项目报错 说数据库中不存在 quartz_LOCKS 这张表 我打开服务器上面的数据上面展示的表名是 quartz_LOCKS&#xff0c;然后通过查询 lower_case_table_names 配置可知 show variables like lower_case_tabl…

Kamailio的SIP服务的性能

官方的性能报告&#xff1a; Kamailio (OpenSER) 1.2.0 - Transaction Module and User Location Performance Tests 如下的提取的性能参数也是基于官方的性能报告&#xff0c;信令走的UDP&#xff0c;作为做系统方案的参照&#xff0c;Kamailio的性能还是非常&#xff0c;非常…

leetcode代码记录(盛最多水的容器

目录 1. 题目&#xff1a;2. 我的代码&#xff1a;小结&#xff1a; 1. 题目&#xff1a; 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以…

【Hibernate-Validate】常用注解

常用注解: NotNull:被注释的元素(任何元素)必须不为 nul, 集合为空也是可以的。NotEmpty:用来校验字符串、集合、map、数组不能为null或也不能为空(字符串传入空格也不可以)(集合需至少包含一个元素)NotBlank:被注释的字符串的必须非空&#xff0c;空格也不行&#xff0c;空字…

来吧伙计们,让AI教我们怎么说海盗语

“如果想伺机而动&#xff0c;就是这样。”——杰克船长提到海盗&#xff0c;我们往往联想到约翰尼德普在《加勒比海盗》中饰演的杰克船长。我们有什么理由不喜欢海盗呢&#xff1f;他们航行在海上&#xff0c;寻找埋藏的宝藏&#xff0c;痛饮朗姆酒&#xff0c;用自己独特的海…

FreMIM:傅里叶变换与遮罩的图像建模在医学图像分割中的应用

代码链接&#xff1a;GitHub - Rubics-Xuan/FreMIM: This repo holds the official code for the paper "FreMIM: Fourier Transform Meets Masked Image Modeling for Medical Image Segmentation". 论文链接&#xff1a;https://arxiv.org/abs/2304.10864 收录于…

差旅补助解决方案|数字化差补赋能业务提效

长期以来&#xff0c;差旅补助一直是企业为了激励员工出差并表达对员工的关怀而采取的一种方式&#xff0c;以经济和福利支持来鼓励员工积极投入工作。然而&#xff0c;由于传统差旅补助的核算、发放和管理方式存在诸多问题&#xff0c;往往适得其反&#xff0c;无法实现企业的…

RocketMQ 面试题及答案整理,最新面试题

RocketMQ的消息存储机制是如何设计的&#xff1f; RocketMQ消息存储机制的设计原理&#xff1a; 1、CommitLog文件&#xff1a; 所有的消息都存储在一个连续的CommitLog文件中&#xff0c;保证了消息的顺序写入&#xff0c;提高写入性能。 2、消费队列&#xff1a; 为每个主…

MySQL row_number()函数,rank()函数和dense_rank()函数

从MySQL8.0开始引用row_number(), rank()函数和dense_rank()函数&#xff0c;也就是常见的窗口函数&#xff0c;三个函数都是一种用于计算排名的工具&#xff0c;它们根据指定的列对结果集进行排序&#xff0c;并为每一行分配一个排名值&#xff08;1,2,3,...&#xff09;。 函…

【漏洞复现】网康科技 NS-ASG 应用安全网关 SQL注入漏洞(CVE-2024-2330)

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

(自用笔记)每天一点vue3—— echarts横坐标刻度标签显示不完全的问题

我是想做一个vue3echarts的账单数据展示项目&#xff0c;因为有vue2的基础&#xff0c;打算直接在这个项目上熟悉掌握vue3的新特性。这系列笔记就按照遇见问题解决问题的思路更新&#xff0c;不按照官方快速上手的章节&#xff0c;特此说明。 echarts 上次遗留一个横坐标刻度标…

strcat函数

函数理解记忆&#xff1a;str表示是<string.g>中的函数&#xff0c;cat表示附加。意思是将一个字符串的内容附加到另一个字符串的末尾。 注意要点&#xff1a;既然要附加&#xff0c;附加的字符串和被附加的字符串都要有\0。否则不知道附加多少&#xff0c;不知附加在哪…

免费视频背景素材下载

找免费视频素材、背景就上这6个网站&#xff0c;高质量&#xff0c;无版权可商用。 1、菜鸟图库 https://www.sucai999.com/video.html?vNTYwNDUx 菜鸟图库虽然是个设计素材网站&#xff0c;但除了设计类素材之外还有很多视频、音频、办公类等素材&#xff0c;视频素材就有上…

前端实现复制粘贴功能

在前端开发的世界里&#xff0c;复制粘贴功能就像是那个总是被忽视&#xff0c;却在关键时刻能救你一命的老朋友。我们习惯了用那些古老的魔法咒语&#xff08;document.execCommand(copy)&#xff09;来实现这一功能&#xff0c;但时代在进步&#xff0c;技术在更新&#xff0…

Frostmourne - Elasticsearch源日志告警配置

简介 配置Frostmourne 接入Elasticsearch源进行日志匹配告警&#xff0c;并静默规则&#xff0c;告警消息发送到企业微信&#xff0c;告警信息使用Markdown。 部署安装教程查看&#xff1a; https://songxwn.com/frostmourne_install ELK 安装教程&#xff1a;https://songx…

综合实验---Web环境搭建

题目&#xff1a; 服务器IP地址规划&#xff1a;client&#xff1a;12.0.0.12/24&#xff0c;网关服务器&#xff1a;ens36:12.0.0.1/24、ens33&#xff1a;192.168.10.1/24&#xff0c;Web1&#xff1a;192.168.10.10/24&#xff0c;Web2&#xff1a;192.168.10.20/24&#xf…

pcl弧度角度换算:rad2deg,deg2rad

角度弧度换算公式: 代码及结果在:cmath 中cos sin等常用函数的坑(弧度角度换算)-CSDN博客 pcl也有自带的rad2deg,deg2rad: 头文件 #include<pcl/common/angles.h> 代码如下 #include <iostream> #include<pcl/common/angles.h> int main() {vector<…

3/13/24运算符、补码、整型、浮点型、汇编

目录 三目运算符 逗号运算符 自增自减运算符 位运算 运算符优先级 补码讲解 整型解析 溢出解析 浮点数IEEE754标准解析 浮点数精度丢失 真题 汇编指令 生成汇编方法 常用指令 三目运算符 条件运算符是C语言中唯一的三目运算符。通过判断问号之前的表达式的真假&…

【随笔记】小程序轮播图,一屏显示三个swiper-item

常见的轮播是一屏显示一个swiper-item,有的时候需要一屏显示三个swiper-item,左右两边都显示出一点 【目前小程序基础库2.12.3 效果正常,3.几的效果会有点不正常】 效果图 wxml <!-- 轮播begin --> <swiper wx:if="{{up_down}}" class="card-swipe…

【C++】thread 头文件无法正常使用问题

问题 当我使用MinGW GCC&#xff0c;在windows上编写C程序的时候&#xff0c;使用thread类会无法编译&#xff0c;有如下错误&#xff1a; 我使用的是c17 这个问题原因是MinGW GCC当前仍缺少标准C 11 及以上版本线程类的实现。 解决方案 Stackoverflow上的类似问题: 传送门…