[数据结构#2] 图(1) | 概念 | 邻接矩阵 | 邻接表 | 模拟

图是由顶点集合及顶点间的关系(边)组成的数据结构,可用 G = ( V , E ) G=(V,E) G=(V,E)表示,其中:

  • 顶点集合 V V V: V = { x ∣ x ∈ 某数据对象集 } V=\{x|x\in\text{某数据对象集}\} V={xx某数据对象集},为有限非空集合;
  • 边集合 E E E: E = { ( x , y ) ∣ x , y ∈ V } E=\{(x,y)|x,y\in V\} E={(x,y)x,yV} E = { ⟨ x , y ⟩ ∣ x , y ∈ V } E=\{\langle x,y\rangle|x,y\in V\} E={⟨x,yx,yV},表示顶点间的关系。

顶点和边

  • 顶点 x x x代表数据元素,第 i i i个顶点记作 v i v_i vi
  • e k e_k ek连接两个顶点,记作 e k = ( v i , v j ) e_k=(v_i,v_j) ek=(vi,vj) ⟨ v i , v j ⟩ \langle v_i,v_j\rangle vi,vj

**分类:有向图与无向图**
  • 有向图:边有方向, ⟨ x , y ⟩ ≠ ⟨ y , x ⟩ \langle x, y \rangle \neq \langle y, x \rangle x,y=y,x
  • 无向图:边无方向, ( x , y ) = ( y , x ) (x, y) = (y, x) (x,y)=(y,x)

**树与图的关系**
  • 是图的一个特殊形式:无环连通图
  • 树的特点
    • 更关注顶点间的结构关系。
    • 二叉搜索树、AVL树等属于存储型数据结构。
  • 图的特点
    • 表示顶点间的关系(如权值)。
    • 可以用于更广泛的场景,如城市地图、社交网络。

常见应用

  1. 社交网络
    • 无向图:如微信好友关系。
    • 有向图:如微博关注关系。

下面的图,顶点可能表示城市,边表示城市之间一个关系(高铁距离、高铁价格、高铁时间。。。)

有了这个东西,提出DFS,BFS遍历,最小生成树(最小代价把图连图),最短路径(一个顶点到其他顶点 或者 多个顶点之间 最短路径)的问题。

完全图

完全图是指任意两个顶点之间都有边相连的图。具体来说:

  • 有n个顶点的无向图中,若有n * (n-1)/2条边(这实际上是一个等差数列求和的结果),即任意两个顶点之间有且仅有一条边,则称此图为无向完全图。例如,上图中的G1就是一个无向完全图。
  • 在n个顶点的有向图中,若有n * (n-1)条边,意味着任意两个顶点之间存在方向相反的两条边,则称此图为有向完全图。如上图中的G4所示。
邻接顶点
  • 在无向图G中,若(u, v)是E(G)中的一条边,则称u和v互为邻接顶点,并称边(u,v)依附于顶点u和v;
  • 在有向图G中,若<u, v>是E(G)中的一条边,则称顶点u邻接到v,而顶点v邻接自顶点u,并称边<u, v>与顶点u和顶点v相关联。
顶点的度

顶点v的度定义为与它相关联的边的数量,记作deg(v)。对于有向图:

  • 顶点v的入度是以v为终点的有向边的数量,记作indev(v);
  • 顶点v的出度是以v为起点的有向边的数量,记作outdev(v)。
    因此,在有向图中,顶点v的总度等于其入度加出度:dev(v) = indev(v) + outdev(v)。
  • 对于无向图,顶点的度等于该顶点的入度和出度之和,即dev(v) = indev(v) = outdev(v)。
  • 类似于树节点的度:子树的个数
路径

在图G = (V, E)中,从顶点vi出发通过一系列边可以到达顶点vj,则称从vi到vj的顶点序列为一条路径。

路径长度
  • 对于不带权的图,路径长度指的是路径上的边的数量;
  • 对于带权的图,路径长度是指路径上所有边的权值总和。
简单路径与回路
  • 如果路径上的所有顶点v1,v2,v3,…,vm都是唯一的,则这样的路径称为简单路径;
  • 若路径的 起始顶点v1和结束顶点vm相同,则这样的路径称为回路或环。

子图

如果一个图G1的所有顶点V1属于另一个图G的顶点集V,且G1的所有边E1也属于G的边集E,则称G1是G的一个子图。

连通图

连通图特指无向图,其中任意一对顶点间都存在至少一条路径。如果一个无向图中的任何一对顶点都可以相互到达,则该图被称为连通图。

强连通图

强连通图是对有向图而言的,指在一个有向图中,对于每一对顶点vi和vj,既存在从vi到vj的路径,也存在从vj到vi的路径。此时称此图为强连通图。

生成树

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


2. 图的存储结构
**存储要素**
  1. 保存顶点信息;
  2. 保存顶点间的关系(边)。
//V 顶点类型,  W 权值类型, Direction  表示有向/无向
template<class V,class W,bool Direction>
class Graph
{private:vector<V> _vertexs;//顶点集合map<V, int> _IndexMap;//顶点与下标映射
};

**2.1 邻接矩阵**

使用二维数组存储顶点关系:

  1. 顶点编号后用下标表示,如 a , b , c , d → 0 , 1 , 2 , 3 a, b, c, d \rightarrow 0, 1, 2, 3 a,b,c,d0,1,2,3
  2. 矩阵值:
    • 若无权图:边对应 1 1 1 0 0 0
    • 若加权图:用权值替代;若无连接,标记为 ∞ \infty

无权图:

加权图:

特点

  • 优点
    • 易于判断两顶点是否连通, O ( 1 ) O(1) O(1)
    • 快速获取边权值。
    • 邻接矩阵存储方式非常适合稠密图
  • 缺点
    • 稀疏图存储低效,存在大量 0 0 0
    • 查找一个顶点的所有邻接点需遍历 O ( N ) O(N) O(N)

假设有n个顶点,是不是要所有顶点遍历一遍才知道某个顶点到底和那些顶点相连。
时间复杂度是O(N),N是顶点个数。

假设有100个顶点,我这个顶点只和三个顶点相连只有三条边,但也要遍历100次,能不能有个方法快速把与之相连的三条边都找到呢?


**2.2 邻接表**

将图表示为顶点数组和链表结合的结构:

  • 顶点数组:保存所有顶点;
  • 边链表:存储某顶点的邻接点及边权值。

邻接表和哈希桶类似。使用一个指针数组,把自己和连接的顶点边都挂在下面。

注意

  • 无向图:同一边在邻接表中存储两次
  • 有向图:边存储一次,出边表表示出度。

无向图邻接表存储

注意:无向图中同一条边在邻接表中出现了两次。如果想知道顶点vi的度,只需要知道顶点vi边链表集合中结点的数目即可

有向图邻接表存储

注意:有向图中每条边在邻接表中只出现一次,与顶点vi对应的邻接表所含结点的个数,就是该顶点的出度,也称出度表,要得到vi顶点的入度,必须检测其他所有顶点对应的边链表,看有多少边顶点的dst取值是i。

一般情况下有向图,存储一个出边表即可。

特点

  • 优点
    • 适合稀疏图;
    • 易于查找某顶点的出边
  • 缺点
    • 判断两顶点是否连通效率低。
      总结一下:邻接矩阵和邻接表其实属于相辅相成,各有优缺点的互补结构。具体还是看场景选择用邻接矩阵和邻接表

图的实现与操作

1. 邻接矩阵实现
**概念简介**

邻接矩阵是一种用于表示图的数据结构。通过一个二维数组来记录顶点间的边关系,可用于无向图和有向图。每个矩阵元素的值代表了边的权重。

**模板设计**
template<class V, class W, W MAX_W = INT_MAX, bool Direction = false>
class Graph {
private:vector<V> _vertexs;        // 顶点集合map<V, int> _IndexMap;     // 顶点到下标的映射vector<vector<W>> _matrix; // 邻接矩阵
  • V: 顶点类型(如int, char
  • W: 权值类型(如int, double
  • MAX_W: 默认最大权值(用来表示不存在的边)
  • Direction: 是否为有向图(默认无向)
**图的创建**

可以通过以下几种方式创建图:

  1. IO输入(适用于在线评测环境)
  2. 文件读取
  3. 手动添加边

针对手动添加边的方式:

Graph(const V* a, size_t n) {_vertexs.reserve(n);for (size_t i = 0; i < n; ++i) {_vertexs.push_back(a[i]);_IndexMap[a[i]] = i;}_matrix.resize(n, vector<W>(n, MAX_W));
}
  • 初始化顶点集合与邻接矩阵。
  • 所有边初始权值为MAX_W(表示“无边”)。
**边的操作**
  • 获取顶点下标
size_t GetVertexindex(const V& v) {auto it = _IndexMap.find(v);if (it != _IndexMap.end()) {return it->second;} else {throw invalid_argument("不存在的顶点");}
}
  • 添加边
void _AddEdge(const size_t& srci, const size_t& dsti, const W& w) {_matrix[srci][dsti] = w;if (!Direction) { // 无向图_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 << "[" << i << "] -> " << _vertexs[i] << endl;}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) {printf("%4c", '*');} else {printf("%4d", _matrix[i][j]);}}cout << endl;}cout << endl;
}

2. 邻接表实现

邻接表是一种用来表示稀疏图的数据结构,使用一个数组结合链表的方式存储。适合存储有大量顶点,但边相对较少的图。

**定义边结构**
template<class W>
struct Edge {size_t _srci, _dsti; // 起始点和目标点的下标W _w;                // 权值Edge<W>* _next;Edge(const size_t& srci, const size_t& dsti, const W& w) : _srci(srci), _dsti(dsti), _w(w), _next(nullptr) {}
};
**图类设计**
template<class V, class W, bool Direction = false>
class Graph {typedef Edge<W> Edge;
private:vector<V> _vertexs;        // 顶点集合map<V, int> _IndexMap;     // 顶点到下标映射vector<Edge*> _tables;     // 邻接表
**图的创建**
Graph(const V* a, size_t n) {_vertexs.reserve(n);for (size_t i = 0; i < n; ++i) {_vertexs.push_back(a[i]);_IndexMap[a[i]] = i;}_tables.resize(n, nullptr);
}
  • 和邻接矩阵一样,初始化顶点集合。
**边的操作**
  • 添加边
void _AddEdge(const size_t& srci, const size_t& dsti, const W& w) {Edge* edge = new Edge(srci, dsti, w);edge->_next = _tables[srci];_tables[srci] = edge;if (!Direction) { // 无向图Edge* new_edge = new Edge(dsti, srci, w);new_edge->_next = _tables[dsti];_tables[dsti] = new_edge;}
}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 << "[" << i << "] -> " << _vertexs[i] << endl;}cout << endl;for (size_t i = 0; i < _tables.size(); ++i) {cout << _vertexs[i] << "[" << i << "] ->";Edge* cur = _tables[i];while (cur) {cout << "[" << _vertexs[cur->_dsti] << ":" << cur->_dsti << ":" << cur->_w << "] ->";cur = cur->_next;}cout << "nullptr" << endl;}cout << endl;
}

sum:

  • 邻接矩阵:适合稠密图,快速判断连通性。
  • 邻接表:适合稀疏图,快速找到某顶点的所有出边。

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

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

相关文章

学习maven(maven 项目模块化,继承,聚合)

前言 本篇博客的核心&#xff1a;理解maven 项目模块化&#xff0c;继承&#xff0c;聚合 的含义 maven 项目模块化 含义 maven项目模块化&#xff1a;使用maven 构建项目&#xff0c;管理项目的方式&#xff0c;我们可以将maven项目根据内在的关系拆分成很多个小项目【模块】…

【OJ题解】最长回文子串

个人主页: 起名字真南的CSDN博客 个人专栏: 【数据结构初阶】 &#x1f4d8; 基础数据结构【C语言】 &#x1f4bb; C语言编程技巧【C】 &#x1f680; 进阶C【OJ题解】 &#x1f4dd; 题解精讲 目录 **题目链接****解题思路****1. 初步判断****2. 回文子串性质****3. 判断是…

EMQX 可观测性最佳实践

EMQX 介绍 EMQX 是一款开源、高度可伸缩、高可用的分布式 MQTT 消息服务器&#xff0c;同时也支持 CoAP/LwM2M 等一站式 IoT 协议接入。以下是 EMQX 的一些主要特点和功能&#xff1a; 海量连接与高并发&#xff1a;EMQX 能够处理千万级别的并发客户端&#xff0c;支持大规模…

kubeadm_k8s_v1.31高可用部署教程

kubeadm_k8s_v1.31高可用部署教程 实验环境部署拓扑图**署架构方案****Load Balance****Control plane node****Worker node****资源分配&#xff08;8台虚拟机&#xff09;**集群列表 前置准备关闭swap开启ipv4转发更多设置 1、Verify the MAC address and product_uuid are u…

mysql flink cdc 实时数据抓取

背景 通过监控mysql日志&#xff0c;获取表字段更新&#xff0c;用来做实时展示。 使用技术&#xff1a;Flink CDC Flink CDC 基于数据库日志的 Change Data Caputre 技术&#xff0c;实现了全量和增量的一体化读取能力&#xff0c;并借助 Flink 优秀的管道能力和丰富的上下游…

element plus el-select修改后缀图标

<el-selectv-model"value"placeholder"请选择工点"size"large":teleported"false":suffix-icon"CaretBottom"style"width: 100px"><el-optionv-for"item in options":key"item.value&quo…

自动驾驶控制与规划——Project 2: 车辆横向控制

目录 零、任务介绍一、环境配置二、算法三、代码实现四、效果展示 零、任务介绍 补全src/ros-bridge/carla_shenlan_projects/carla_shenlan_stanley_pid_controller/src/stanley_controller.cpp中的TODO部分。 一、环境配置 上一次作业中没有配置docker使用gpu&#xff0c;…

Qt6开发自签名证书的https代理服务器

目标&#xff1a;制作一个具备类似Fiddler、Burpsuit、Wireshark的https协议代理抓包功能&#xff0c;但是集成到自己的app内&#xff0c;这样无需修改系统代理设置&#xff0c;使用QWebengineview通过自建的代理服务器&#xff0c;即可实现https包的实时监测、注入等自定义功能…

Windows如何安装Php 7.4

一、进入官网&#xff0c;选择其他版本 https://windows.php.net/download/ 二、配置环境变量 将解压后的php 路径在系统环境变量中配置一下 cmd 后输入 php-v

ensp 静态路由配置

A公司有广州总部、重庆分部和深圳分部3个办公地点&#xff0c;各分部与总部之间使用路由器互联。广州、重庆、深圳的路由器分别为R1、R2、R3&#xff0c;为路由器配置静态路由&#xff0c;使所有计算机能够互相访问&#xff0c;实训拓扑图如图所示 绘制拓扑图 给pc机配置ip地址…

红米Note 9 Pro5G刷LineageOS

LineageOS介绍 LineageOS 是一个基于 Android 的开源操作系统&#xff0c;是面向智能手机和平板电脑等设备的替代性操作系统。它是 CyanogenMod 的继承者&#xff0c;而 CyanogenMod 是曾经非常受欢迎的一个第三方 Android 定制 ROM。 在 2016 年&#xff0c;CyanogenMod 项目因…

ECharts实现数据可视化入门详解

文章目录 ECharts实现数据可视化入门详解一、引言二、基础配置1.1、代码示例 三、动态数据与交互2.1、代码示例 四、高级用法1、多图表组合1.1、在同一容器中绘制多个图表1.2、创建多个容器并分别初始化 ECharts 实例1.3、实现多图联动 五、总结 ECharts实现数据可视化入门详解…

盲盒3.0版h5版-可打包app-新优化版紫色版

整体界面ui美观大气&#xff0c;盲盒项目也是一直比较热门的&#xff0c;各大平台一直自己也有做。 感兴趣的小伙伴可以搭建做自己的项目。盲盒项目的利润率还是很大的。

MacbookPro M1 安装Hive

前提注意⚠️⚠️⚠️ 1&#xff09;在安装Hive前确实需要安装MySQL&#xff0c;因为Hive可以使用MySQL作为元数据存储 2&#xff09;在安装Hive之前&#xff0c;需要先安装Hadoop。Hive是一个构建在Hadoop之上的数据仓库软件&#xff0c;它使用Hadoop的HDFS&#xff08;分布…

Crawl4AI:一个为大型语言模型(LLM)和AI应用设计的网页爬虫和数据提取工具实战

这里写目录标题 一、crawl4AI功能及简介1、简介2、特性 二、项目地址三、环境安装四、大模型申请五、代码示例1.生成markdown2.结构化数据 一、crawl4AI功能及简介 1、简介 Crawl4AI 是一个开源的网页爬虫和数据抓取工具&#xff0c;一个python项目&#xff0c;主要为大型语言…

游戏引擎学习第50天

仓库: https://gitee.com/mrxiao_com/2d_game Minkowski 这个算法有点懵逼 回顾 基本上&#xff0c;现在我们所处的阶段是&#xff0c;回顾最初的代码&#xff0c;我们正在讨论我们希望在引擎中实现的所有功能。我们正在做的版本是初步的、粗略的版本&#xff0c;涵盖我们认…

深度解读:Top14金融顶刊

作者Toby&#xff1a;来源&#xff1a;Python风控模型&#xff0c;Top14金融顶刊 各位同学好&#xff0c;我是Toby老师&#xff0c;今天为大家介绍金融风控领域的顶级学术期刊&#xff0c;用于小论文发布平台参考。 金融风控领域内有许多顶级学术期刊&#xff0c;它们发表高质…

数据库管理-第271期 Oracle 23ai:用MongoDB的方式来操作JSON二元性(20241214)

数据库管理271期 2024-12-14 数据库管理-第271期 Oracle 23ai&#xff1a;用MongoDB的方式来操作JSON二元性&#xff08;20241214&#xff09;1 初始化数据1.1 创建用户1.2 导入数据1.3 创建JSON关系二元性视图 2 创建ORDS服务2.1 下载JDK172.2 安装ORDS2.3 启用MongoDB API2.4…

计网_虚拟局域网VLAN

2024.12.08&#xff1a;计算机网络虚拟局域网VLAN学习笔记 虚拟局域网VLAN VLAN背景&#xff08;认真看&#xff09;VLAN定义&#xff08;最大的好处是隔离广播域&#xff09;VLAN以太网帧格式的扩展划分虚拟局域网VLAN的方式虚拟局域网的优点 VLAN背景&#xff08;认真看&…

使用ENSP实现NAT(2)

一、NAT的类型 二、静态NAT 1.项目拓扑 2.项目实现 路由器AR1配置&#xff1a; 进入系统视图 sys将路由器命名为AR1 sysname AR1关闭信息中心 undo info-center enable 进入g0/0/0接口 int g0/0/0将g0/0/0接口IP地址配置为192.168.10.254/24 ip address 192.168.10.254 24进…