「re: 从零开始的带学数据结构㈡」图的一点基础理解
这部分为了快速入坑参考了浙大的课程,邓俊辉那个由于自己 C++ 基础太拉胯了就换了个简单的 www。后面还有一些细节的地方懒得搞了,反正写了这文章也图一乐 2333333,以后再润色了(
「re: 从零开始的带学数据结构㈡」图的一点基础理解
图的相关定义
概论
线性表和树本身是图的特殊情形。线性表和树表示的是一对一和一对多的关系,而图表示的是多对多的关系。包含:
一组顶点(Vertex)
一组边(Edge)
其中:
边是顶点对, (v, w) ∈ E,其中 v, w ∈ V;
有向边 <v, w> 表示从 v 指向 w 的边(单行线);
不考虑自回路
简单路径:不经过相同的顶点。
邻接:顶点和顶点
关联:顶点和边
ADT
表示方法
邻接矩阵
G [N] [N]
,N 个顶点从 0 到 N-1 编号。
- 注意:二维数组的顺序是
A [X] [Y]
。分别代表 X 位置和 Y 位置。
其中 G [I] [J] = 1
,若 <vi, vj>
是 G
中的边;否则是 0.
直观。方便找邻接点、边、计算度(出度、入度)。但面对稀疏图的时候会浪费空间。
邻接表
G [N] 是指针数组,对应矩阵每行一个链表,只存非 0 元素。
节约稀疏图的空间、便于计算出度。但不便检查顶点间的边、也不便计算入度。
图的遍历
广度优先搜索(BFS)
一套矩阵图的 BFS 实现。本质上是个队列的操作,按顺序压进去也就相当于按照广度优先的顺序。
1 | //广度优先搜索的简化重载函数。 |
深度优先搜索(DFS)
伪代码实现:
1 | void DFS(Vertex V) |
最短路径问题
在网络中,求两个不同顶点之间的所有路径中,边的权值之和最小的一条路径。这条路径(源点 - 终点)的路径就是最短路径。
分为:
- 单源:对从某固定源点出发,到其他顶点
- 多源:任意两顶点。
单源带权图最短路径问题——Dijkstra 算法(视频理解)
前提
给定两个数组 Distance
和 Previous
来表示目标点到不同点的距离,以及达到这个路径需要走的前一个节点。
过程
初始化:先利用 flag 标记源点(下例表示为 V0),代表收入到最短路线集合里面;并且计算 V0 到邻接点的距离,存入 Distance 数组内,上一个元素显然是 V0,故存入 Previous 中。
循环开始:每次找未标记的节点里面距离出发点最近(Distance 最小)的节点。标记、收录到最短路线集合里面。
计算它到邻接点的距离,如果端点 P 和邻接点 A 之间满足: \[ Dist[A] < Dist[P] + Edge<P, A> \] 那么就把邻接点的 Distance[A] 和 Previous[A] 更新。(松弛)
每步取最优的操作是贪心算法思想的体现。
实现
1 | //Dijkstra 算法。有权图的情况。 |
多源最短路算法——Floyd 算法
前提
调用 V 次 Dijkstra
之类的算法也可以暴力解决多源最短路算法。它的时间复杂度是
O(V^3 + V*E)
,但只在稀疏图可以实现 Floyd 算法的程度,达到
O(V^3)
的水平。
过程
代码实现
最小生成树
前提
树:无回路,边比顶点少一个。
生成:包含所有顶点,边都在图内。
权重和最小。
最小生成树存在,图一定联通。
算法分析
贪心算法可以在这个问题应用:
- 每一步取最优结果——代表权重最小的边
- 约束情况:只能用图中的边、正好用掉 V-1 条、不能有回路
方法 1:Prim 算法
Prim 算法的基本思路是:从一个根节点开始,慢慢地建立起一棵树。每次选权重最小的来生成。如果最后节点数量不够,就说明图不连通,生成失败。
伪代码实现:
1 | void Prim() |