图 的 基 础 知 识 \color{FCE6C9}{图的基础知识} 图的基础知识
o 术语
-
顶点 Vertex
-
弧 Arc <u , v> :从u到v的弧。u:弧尾;v:弧头
-
边 Edge
-
入度:ID(v) ; 出度:OD(v) ; 度:TD(v)
*o 存储方法
-
邻接矩阵
-
无向图只用压缩存储一个三角矩阵即可
-
有向图要全部存储
-
-
邻接表P219
-
表头结点表:由所有表头结点以顺序结构(向量)的形式存储,以便可以随机访问任一顶点的边链表。表头结点由两部分构成,其中数据域vexdata用于存储顶点的名或其他有关信息;链域firstarc用于指向链表中第一个顶点(即与顶点 v i v_{i} vi邻接的第一个邻接点)
-
边表:由表示图中顶点间邻接关系的n个边链表组成。边链表中结点的结构由三部分组成,其中邻接点域adjvex用于存放与顶点 v i v_{i} vi相邻接的顶点在图中的位置;链域nextarc用于指向与顶点 v i v_{i} vi相关联的下一条边或弧的结点;数据域info用于存放与边或弧相关的信息(如赋权图中每条边或弧的权值等)。
-
-
十字链表(OrthogonalList)P221
- 有向图的另一种链式存储结构,可以把它看成是将有向图的邻接表和逆邻接表结合起来的一种链表。有向图中的每一条弧对应十字链表中的一个弧结点,同时有向图中的每个顶点在十字链表中对应有一个结点,称为顶点结点。
o 应用
-
简单路径
-
遍历 P225-231
-
广度优先(队列)
-
深度优先(栈)
-
-
生成树和最小生成树
-
概念:
-
生成树:一个连通图的生成树是指一个极小连通子图,它含有图中的全部顶点,但只有足以构成一棵树的n-1条边。如果在一棵生成树上添加一条边,必定构成一个环,这是因为该条边使得它依附的两个顶点之间有了第二条路径
-
最小生成树:各边的代价之和最小的生成树(MST)
-
-
算法:
-
Prim普里姆算法(最小生成树,加点法)
- 假设N=(V,{E})是连通网,TE是最小生成树中边的集合
-
初始U={u0}(u0属于V),TE为空集
-
在所有的u属于U,v属于V-U的边中选一条代价最小的边放进TE,v0放进U
-
重复(2)直到U=V
- 此时,TE中有n-1条边,则T必然是N的最小生成树
-
- 算法步骤:
-
初始顶点u加入集合U,剩余的每个顶点i,将CloseEdge[i]初始化为i到u的边信息
-
循环n-1次:
-
从各组最小边CloseEdge[]里选择最小的最小边ClodeEdge[v](v属于V-U)
-
v加入U
-
更新剩余节点的最小边信息CloseEdge[i](i属于V-U)
-
-
- 假设N=(V,{E})是连通网,TE是最小生成树中边的集合
-
kruskal克鲁斯卡尔算法(加边法):
-
找最小生成树(各边代价之和最小的生成树(连通子图))
-
将n个顶点看成n个集合
-
按照权值由小到大选择边,满足:边的两端点在不同集合中。将该边放到生成树的边集合里,合并该边的端点集合
-
重复(2)。直到只有一个顶点集
-
(注意:加边不能形成回)
-
更适合于稀疏的连通图
-
-
-
-
-
有向无环图的应用:《数据结构》P243-249
-
拓扑排序:
-
概念:
-
AOV-网:用顶点表示活动的网。用顶点表示活动,弧表示活动间优先关系
-
拓扑序列:先后关系的序列(可能不唯一)
-
-
思想:
-
选取无前驱的节点并记录此节点
-
删除此节点和相连的边
-
重复,直到不存在没有前驱的节点
-
若此时记录的节点小于总节点数,说明有环。否则记录的是一个拓扑排序
-
-
基于邻接矩阵G的算法:
-
第一个序号k=1
-
找一个未新编号且值全为0的列。若找到,继续(3);否则,若所有列都已经编号,排序结束,若还有列没有编号,则存在回路
-
输出(2)找到的列对应的顶点j,把新序号k赋给(2)中找到的列
-
j对应的行全部置为0
-
序号k++,转(2)
-
-
基于邻接表G的算法:
-
查找indegree[i]为0的顶点i
-
对链在i后面的所有邻接顶点j,对应的indegree[j]减一
-
为避免重复检测入度为0的点,设一辅助栈S,将入度为0的顶点入栈。
-
只要栈不空,重复:{栈顶元素i出栈并打印 -> i的每个邻接点k的入度减1,若k入度变为0,k入栈}
-
-
-
关键路径
-
概念:
-
AOE-网:边表示活动的网。用顶点表示时间,边的权值表示所需时间(记顶点为v,边为a,即通常事件为v,活动为a)
-
源点:唯一的、入度为0的节点
-
汇点:唯一的、出度为0的节点
-
关键路径:从源点到汇点的最长路径长度即是完成活动所需的总时间
-
关键活动:关键路径上的活动
-
事件v的最早发生时间:源点到v的最长路径长度
-
事件v的最晚发生时间(在保证汇点最早发生的前提下):从汇点开始,逆拓扑顺序向源点递推
-
活动a开始的最早时间:从源点到弧a的始点最长路径
-
活动a开始的最晚时间:倒推
-
活动a松弛时间(时间余量):a的最早开始时间与最晚开始时间之差
-
-
关键路径步骤:
-
进行拓扑排序,排序时按照拓扑序列求出每个事件的最早发生时间ve(i)(程序如上)
-
按照逆拓扑序列求出事件最晚发生时间vl(i)
-
求出每个活动a(i)的最早开始时间e(i)和最晚发生时间l(i)
-
e(i)=l(i)为所求
-
-
算法思想:(部分功能已在TopOrder实现)
-
求出各个顶点入度,入度为0则入栈S
-
初始化各顶点最早发生时间为ve[i]=0
-
当栈S不空,重复:
-
S栈顶元素j出栈,并压入T(生成逆拓扑序列)
-
对链在j后面的所有邻接顶点k,对应的indegree[k]减一。若此时入度为0,则对应节点入栈S
-
根据顶点j的最早发生时间和ve[j]和弧<j,k>的权值,更新k的最早发生时间
-
-
-
-
-
最短路径
-
迪杰斯特拉算法
-
求给定顶点到其他顶点的最短路径
-
时间复杂度:O( n 3 n^3 n3)
-
空间复杂度:O(n)
-
操作:
-
对图G={V,|E|},将顶点分为两组:
第一组S:已经求出的最短路径的终点集合(开始为{v0});
第二组V-S:尚未求出最短路径的集合(开始为V-{v0}的全部节点) -
按照长度递增顺序,把第二组的加进第一组,即先把最短的加进第一组,直到加完
-
-
-
弗洛伊德算法
-
从任意顶点到其他顶点的最短路径
-
时间复杂度:O( n 3 n^3 n3)
-
空间复杂度:O( n 2 n^2 n2) //用了一个二维数组
-
操作:
- 将
v
i
v_{i}
vi 到
v
j
v_{j}
vj 的最短的路径长度初始化为g.arcs[i][j].adj,然后进行如下n次比较和修正:
- v i v_{i} vi 与 v j v_{j} vj间加入顶点 v 0 v_{0} v0,比较( v i v_{i} vi, v 0 v_{0} v0, v j v_{j} vj )的路径长度,取其中较短的路径作为 v i v_{i} vi到 v j v_{j} vj的且中间顶点号不大于0的最短路径。
- 在 v i v_{i} vi 与 v j v_{j} vj 间加入顶点 v 1 v_{1} v1,得到( v i v_{i} vi, … , v 1 v_{1} v1 ) 和 ( v 1 v_{1} v1,…, v j v_{j} vj),其中( v i v_{i} vi, … , v 1 v_{1} v1 )是 v i v_{i} vi 到 v 1 v_{1} v1 的且中间顶点号不大于0的最短路径,( v 1 v_{1} v1, … , v j v_{j} vj )是 v 1 v_{1} v1 到 v j v_{j} vj 的且中间顶点号不大于0的最短路径,这两条路径在上一步中已求出。将( v i v_{i} vi, … , v 1 v_{1} v1 , …, v j v_{j} vj)与上一步已求出的 v i v_{i} vi到 v j v_{j} vj中间顶点号不大于0的最短路径比较,取其中较短的路径作为 v i v_{i} vi到 v j v_{j} vj的且中间顶点号不大于1的最短路径。
- 在n,与v,间加人顶点 v 2 v_{2} v2得( v i , . . . v 2 v_{i},...v_{2} vi,...v2)和( v 2 v_{2} v2, … v j v_{j} vj), 其中( v i , . . . v 2 v_{i},...v_{2} vi,...v2)是 v i 到 v 2 v_{i}到v_{2} vi到v2的且中间顶点号不大于1的最短路径, ( v 2 v_{2} v2, … v j v_{j} vj)是 v 2 v_{2} v2到 v j v_{j} vj的且中间顶点号不大于1的最短路径,这两条路径在上一步中已求出。将(v_{i}, … v_{2}, … v_{j})与上一步已求出的 v i v_{i} vi 与 v j v_{j} vj且中间顶点号不大于1的最短路径比较,取其中较短的路径作为 v i v_{i} vi 到 v j v_{j} vj的且中间顶点号不大于2的最短路径。
- 以此类推,经过n次比较和修正,在第n-1步,将求得 v i v_{i} vi 到 v j v_{j} vj的且中间顶点号不大于n-1的最短路径,这必是从 v i v_{i} vi 到 v j v_{j} vj的最短路径。
- 图g中所有顶点偶对 v i v_{i} vi 与 v j v_{j} vj间的最短路径长度对应一个n阶方阵D。在上述n+1步中,D的值不断变化,对应一个n阶方阵序列。
- 定义:n阶方阵序列
D
−
1
,
D
0
,
D
1
,
.
.
.
D
n
D^{-1}, D^0, D^1, ... D^n
D−1,D0,D1,...Dn, 其中,
D − 1 D^{-1} D−1[i][j]=g.arcs[i][j].adj
D k D^k Dk[i][j]=Min{ D k − 1 D^{k-1} Dk−1[i][j], D k − 1 D^{k-1} Dk−1[i][k] + D k − 1 D^{k-1} Dk−1[k][j] } ,0≤k≤n-1 - 显然, D N − 1 D^{N-1} DN−1中为所有顶点偶对 v i v_{i} vi 与 v j v_{j} vj 间的最终最短路径长度。
- 将
v
i
v_{i}
vi 到
v
j
v_{j}
vj 的最短的路径长度初始化为g.arcs[i][j].adj,然后进行如下n次比较和修正:
-
-