数据结构:七 图
1. 图的定义
定义
-
图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E)
-
G 表示一个图,V 是图 G 中顶点的集合,E 是图 G 中边的集合
-
线性表中我们把数据元素叫元素,树中将数据元素叫结点,在图中数据元素,我们则称之为顶点(Vertex)
-
在图结构中,不允许没有顶点。在定义中,若 V 是顶点的集合,则强调了顶点集合 V 有穷非空
- 线性表中可以没有数据元素,称为空表
- 树中可以没有结点,叫做空树
-
图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的
- 线性表中,相邻的数据元素之间具有线性关系
- 树结构中,相邻两层的结点具有层次关系
-
各种图定义
-
无向边:若顶点 vi 到 vj 之间的边没有方向,则称这条边为无向边(Edge),用无序偶对(vi,vj)来表示
-
有向边:若从顶点 vi 到 vj 的边有方向,则称这条边为有向边,也称为弧(Arc)
- 用有序偶 <vi,vj> 来表示,vi 称为弧尾(Tail),vj 称为弧头(Head)
-
简单图:在图中,若不存在顶点到其自身的边,且同一条边不重复出现
-
无向完全图:在无向图中,如果任意两个顶点之间都存在边
-
有向完全图:在有向图中,如果任意两个顶点之间都存在方向互为相反的两条弧
-
有很少条边或弧的图称为稀疏图,反之称为稠密图
-
权(Weight):与图的边或弧相关的数
- 这些权可以表示从一个顶点到另一个顶点的距离或耗费
- 这种带权的图通常称为网(Network)
图的顶点与边间关系
- 对于无向图 G=(V,{E}),如果边(v,v')属于 E,则称顶点 v 和 v' 互为邻接点(Adjacent),即 v 和 v' 相邻接
- 边(v,v')依附(incident)于顶点 v 和 v',或者说(v,v')与顶点 v 和 v' 相关联
- 顶点 v 的度(Degree)是和 v 相关联的边的数目,记作 TD(v)
- 路径的长度是路径上的边或弧的数目
- 第一个顶点到最后一个顶点相同的路径称为回路或环(Cycle)
- 序列中顶点不重复出现的路径称为简单路径
- 除了第一个顶点和最后一个顶点之外,其余顶点不重复出现的回路,称为简单回路或简单环
-
连通图相关术语
-
在无向图 G 中,如果从顶点 v 到顶点 v' 有路径,则称 v 和 v' 是连通的。
-
如果对于图中任意两个顶点 vi vj 属于 E ,vi 和 vj 都是连通的,则称 G 是连通图(Connected Graph)
-
无向图中的极大连通子图称为连通分量
- 要是子图
- 子图是连通的
- 连通子图含有极大顶点数
- 具有极大顶点数的连通子图包含依附于这些顶点的所有边
-
在有向图 G 中,如果对于每一对 vi vj 属于 V,vi 不等于 vj,从 vi 到 vj 和从 vj 到 vi 都存在路径,则称 G 是强连通图
-
有向图中的极大强连通子图称做有向图的强连通分量
-
连通图的生成树定义
- 一个连通图的生成树是一个极小的连通子图,它含有图中全部的 n 个顶点,但只有足以构成一棵树的 n-1 条边
- 如果一个有向图恰有一个顶点的入度为 0,其余顶点的入度为 1,则是一棵有向树
- 一个有向树的生成森林由若干棵有向树组成,含有图中全部顶点,但只有足以构成若干棵不相交的有向树的弧
2. 图的抽象数据类型
ADT 图(Graph) Data 顶点的有穷非空集合和边的集合 Operation CreateGraph(*G,V,VR):按照顶点集V和边弧集VR的定义构造图G DestroyGraph(*G):图G存在则销毁 LocateVex(G,u):若图G中存在顶点u,则返回图中位置 GetVex(G,v):返回图中顶点v的值 PutVex(G,v,value):将图G中顶点v赋值给value FirstAdjVex(G,*v):返回顶点v的一个邻接顶点,若顶点在G中无邻接顶点则返回空 NextAdjVex(G,v,*w):返回顶点v相对于顶点w的下一个邻接顶点,若w是v的最后一个邻接点则返回空 InsertVex(*G,v):在图G中增加新顶点v DeleteVex(*G,v):删除图G中顶点v及其相关的弧 InsertArc(*G,v,w):在图G中添加弧<v,w>,若G是无向图,还需要添加对称弧<w,v> DeleteArc(*G,v,w):在图G中删除弧<v,w>,若G是无向图,则需要删除对称弧<w,v> DFSTraverse(G):对图G中进行深度优先遍历,在遍历过程对每个顶点调用 HFSTraverse(G):对图G中进行广度优先遍历,在遍历过程对每个顶点调用
endADT
3. 图的存储结构
邻接矩阵
-
图的邻接矩阵(Adjacency Matrix)存储方式是用两个数组来表示图
- 一个一维数组存储图中顶点信息
- 一个二位数组(称为邻接矩阵)存储图中的边或弧的信息
-
对称矩阵:n 阶矩阵的元满足 aij = aji(0 <= i, j <= n)
-
邻接表
-
数组与链表相结合的存储方法称为邻接表(Adjacency List)
- 图中顶点用一个一维数组存储,当然,顶点也可以用单链表来存储,不过数组可以较容易地读取顶点信息,更加方便
- 另外,对于顶点数组中,每个数据元素还需要存储指向第一个邻接点的指针,以便于查找该顶点的边信息
- 图中每个顶点 vi 的所有邻接点构成一个线性表,由于邻接点的个数不定,所以用单链表存储,无向图称为顶点 vi 的边表,有向图则称为顶点 vi 作为弧尾的出边表
-
-
无向图的邻接表结构
-
顶点表的各个结点由 data 和 firstedge 两个域表示
- data 是数据域,存储顶点的信息,
- firstedge 是指针域,指向边表的第一个结点,即此顶点的第一个邻接点
-
边表结点由 adjvex 和 next 两个域组成
- adjvex 是邻接点域,存储某顶点的邻接点在顶点表中的下标
- next 则存储指向边表中下一个结点的指针
-
-
有向图的逆邻接表
- 对每个顶点 vi 都建立一个链接为 vi 为弧头的表
- 对带权值得网图,可在边表结点定义中再增加一个 weight 的数据域,存储权值信息即可
十字链表
-
重新定义顶点表结点结构
- firstin 表示入边表头指针,指向该顶点的入边表中第一个结点
- firstout 表示出边表头指针,指向该顶点的出边表中的第一个结点
-
-
重新定义边表结点结构
- tailvex 是指弧起点在顶点表的下标
- headvex 是指弧终点在顶点表中的下标
- headlink 是指入边表指针域,指向终点相同的下一条边
- taillink 是指边表指针域,指向起点相同的下一条边
- 如果是网,还可以增加一个 weight 域来存储权值
邻接多重表
-
重新定义边表结点结构
- ivex 和 jvex 是与某条边依附的两个顶点在顶点表中下标
- ilink 指向依附顶点 ivex 的下一条边
- jlink 指向依附顶点 jvex 的下一条边
边集数组
-
边集数组是由两个一维数组构成
- 一个是存储顶点的信息
- 另一个是存储边的信息,这个边数组每个数据元素由一条边的起点下标(begin),终点下标(end)和权(weight)组成
-
定义的边数组结构
- begin 是存储起点下标,end 是存储终点下标,weight 是存储权值
4. 图的遍历
从图中某一顶点出发访遍图中其余顶点,且使每一个顶点仅被访问一次,这过程叫图的遍历
深度优先遍历(Depth First Search,DFS)
-
对于连通图
- 从图中某个顶点 v 出发,访问此顶点,然后从 v 的未被访问的邻接点出发深度优先遍历图,直至图中所有和 v 有路径相通的顶点都被访问到
-
对于非连通图
- 只需要对它的连通分量分别进行深度优先遍历,即在先前一个顶点进行一次深度优先遍历后,若图中尚有顶点未被访问,则另选图中一个未曾被访问的顶点作起始点,重复上述过程,直至图中所有顶点都被访问到为止
-
图的深度优先遍历类似树的前序遍历
-
深度遍历更适合目标明确,以找到目标为主要目的
广度优先遍历(Breadth First Search,BFS)
- 图的广度优先遍历就类似于树的层序遍历
- 广度优先更适合在不断扩大遍历范围时找到相对最优解
5. 最小生成树
定义
- 构建连通网的最小代价生成树
普利姆(Prim)算法
- 以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树
克鲁斯卡尔(Kruskal)算法
6. 最短路径
定义
-
非网图
- 由于非网图它没有边上的权值,所谓的最短路径,其实就是指两顶点之间经过的边数最少的路径
-
网图
- 对于网图来说,最短路径是指两顶点之间经过的边上权值之和最少的路径,并且我们称路径上的第一个顶点是源点,最后一个顶点是终点
迪杰斯特拉(Dijkstra)算法
弗洛伊德(Floyd)算法
7. 拓扑排序
拓扑排序介绍
-
AOV 网(Activity On Vertex Network)
- 在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,我们称为 AOV 网
-
拓扑序列
- 设 G=(V, E) 是一个具有 n 个顶点的有向图,V 中的顶点序列 v1,v2,······,vn,满足若从顶点 vi 到 vj 有一条路径,则在顶点序列中顶点 vi 必在顶点 vj 之前。则我们称这样的顶点序列为一个拓扑序列
-
拓扑排序
-
对一个有向图构造拓扑序列的过程
-
构造时会有两个结果
- 如果此网的全部顶点都被输出,则说明它是不存在环(回路)的 AOV 网
- 如果输出顶点数少了,哪怕是少了一个,也说明这个网存在环(回路),不是 AOV 网
-
拓扑排序算法
-
基本思路
- 从 AOV 网中选择一个入度为 0 的顶点输出,然后删除此顶点,并删除以此顶点为尾的弧,继续重复此步骤,直到输出全部顶点或者 AOV 网中不存在入度 0 的顶点为止
8. 关键路径
定义
-
AOE 网
- 在一个表示工程的带权有向图中,用顶点表示事件,用有向边表示活动,用边上的权值表示活动的持续时间,这种有向图的边表示活动的网,我们称之为 AOE 网(Activity On Edge Network)
- 没有入边的顶点称为始点或源点
- 没有出边的顶点称为终点或汇点
- 由于一个工程,总有一个开始一个结束,所以正常情况下,AOE 网只有一个源点一个汇点
-
路径长度:路径上各个活动所持续的时间之和
-
关键路径:从源点到汇点具有最大长度的路径
-
关键活动:在关键路径上的活动
关键路径算法原理
-
找到所有活动的最早开始时间和最晚开始时间,并且比较它们,如果相等就意味着此活动是关键活动,活动间的路径为关键路径;如果不等,则就不是
-
参数定义
-
事件的最早发生时间 etv(earliest time of vertex)
- 即顶点 vk 的最早发生时间
-
事件的最晚发生时间 ltv(latest time of vertex)
- 即顶点 vk 的最晚发生时间,也就是每个顶点对应的事件最晚需要开始的时间,超出此时间将会延误整个工期
-
活动的最早开工时间 ete(earliest time of edge)
- 即弧 ak 的最早发生时间
-
活动的最晚开工时间 lte(latest time of edge)
- 即弧 ak 的最晚发生时间,也就是不推迟工期的最晚开工时间
-
关键路径算法