【数据结构:图】

一、基本概念

1. 什么是图?

图G = (V, E) , V:有穷顶点集; E:边集

无向图:(v1, v2) = (v2, v1) 顶点对无序
有向图:<v1, v2> 不等于 <v2, v1>, 顶点对有序

2. 什么是子图?

顶点和边相应包含在主图
在这里插入图片描述

3. 什么是加权图?

图的每条边对应一个权值。权可以代表费用,时间长度等。

4. 什么是相关联?

指的是顶点与边之间的关系。

(1) 设G=(V, E)是无向图,若边(V1, V2)属于E,则称V1、V2是相邻顶点,边(V1, V2)是与顶点V1、V2相关联的边。
(2) 设G=(V,E)是有向图,若边<V1, V2>属于E,则称V1邻接到V2,V2邻接于V1,边<V1, V2>是顶点V1和V2相关联的边。

5. 什么是度?

(1)无向图中:
V1的度:与顶点V1相关联的边数和

(2)有向图中:
出度:以顶点V1为始点,并与V1相关联的边数
入度:以顶点V1为终点,并与V1相关联的边数
V1的度 = 出度 + 入度

终端顶点(叶子结点):有向图中,出度为0的顶点。

试题:
在这里插入图片描述

6. 什么是简单图?

(1)简单无向图:任意两个顶点之间最多一条边,且不含自回路。

(2)简单有向图:任意两个顶点之间最多两条相反的边,且不含自回路。

试题:
在这里插入图片描述

7. 什么是完全图?

(1)无向完全图:任意两个顶点之间都有一条边的简单无向图。含有n个顶点的无向完全图有n*(n-1)/2条边

(2)有向完全图:任意两个顶点之间都有反向相反的两条边的简单有向图。含有n个顶点的有向完全图有n*(n-1)条边。

8. 什么是路径?

(1)路径:有向(或无向)图中,无重复边相邻前后边衔接的边序列称为从V1到Vn的一条路径。序列中的边数称为路径的长度。

(2)简单路径:除了V1和Vn可以相等,路径上所有的顶点各不相同。

(3)回路/环:V1 = Vn的简单路径

试题:
(1).
在这里插入图片描述
(2) 注意:简单路径一定是路径
在这里插入图片描述

9. 什么是连通图/强连通图?

(1)连通图:无向图 G中,任意两个顶点Vi和Vj之间有路径

(2)强连通图:有向图 G中,任意两个顶点Vi和Vj, 存在Vi到Vj的路径,以及Vj到Vi的路径。

10. 什么是连通分量/强连通分量?

(1) 连通分量:无向图极大连通子图。如:
在这里插入图片描述
在这里插入图片描述

(2) 强连通分量:有向图极大强连通子图。如:
在这里插入图片描述在这里插入图片描述

11. 什么是生成树?

(1) 生成树:
含有n个顶点的连通无向图G的生成树是G的一个含有全部n个顶点和n-1条边的连通图
(即含有全部n个顶点的极小连通子图

(2) 生成森林:
含m个连通分量的无向图的每个连通分量都有一棵生成树,构成图的生成森林。
在这里插入图片描述

二、图的存储表示

引言:考虑调用scanf()输入一个图?如何设计输入格式?在内存如何保存一个图?

1. 矩阵

1.1 如何用相邻矩阵表示图?

在这里插入图片描述
在这里插入图片描述

1.2 如何用相邻矩阵表示加权图?

在这里插入图片描述

1.3 如何用相邻矩阵存储图?

(1)用相邻矩阵表示图
a. 需要一个顺序表存储n个顶点
b. 需要一个nn的矩阵存储边
对于有向图,需要n^2个单元
对于无向图,只需要存储矩阵的上三角或者下三角,只需n
(n-1)/2个单元

(2)思考:矩阵有何缺点?如何克服?

2. 邻接表

2.1如何用邻接表存储图?

邻接表由顶点表和边表组成

(1)无向图:对于每个顶点,将与顶点相关联的边组织一个链表,称为边表。顶点表的每个表项对应一个顶点,保存与该顶点相关联的表头指针。
在这里插入图片描述
在这里插入图片描述

(2)有向图:可以将与顶点相关联的出边组织成链表,作为与该顶点相关联的边表,称为出边表;或者将所有入边组织成链表,称为入边表。
在这里插入图片描述

2.2 结论

(1)邻接表表示加权图(网), 只需在边表的每个结点加上一个表示权的字段。
(2)邻接表存储具有n个顶点、m条边的图:
a. 顶点表n个表项
b. 无向图的所有边表共有2m个表项
c. 有向图的所有边表共有m个表项

2.3 思考

邻接表表示无向图时,每条边对应两个边表结点,不利于插入、删除等操作。如何修改邻接表,使得每条边只对应一个边表结点?
在这里插入图片描述

3. 邻接多重表

3.1 如何用邻接多重表存储无向图

邻接多重表由顶点表和边表组成,每条边只对应一个边表结点。 注意:

(1)顶点表结点包含data域和edge域(指向与该顶点相关联的第一条边)
在这里插入图片描述

(2)边表结点包含5个域:
mark:边访问标记
i,j:边(Vi, Vj)的两个顶点的标号
ilink:指向与Vi相关联的下一条边
jlink:指向与Vj相关联的下一条边
在这里插入图片描述

练习:
在这里插入图片描述
在这里插入图片描述

  • 如何用邻接多重表存储有向图
    邻接表表示有向图时只保存顶点的入边表或出边表。
    有向图的邻接多重表同时能表示顶点的出边和入边,而不增加边表节点数。
    有向图的邻接多重表包含顶点表和边表:
    (1)顶点表的每个表项包含3个域:
    data:表示顶点信息
    edge1:指向以该顶点为始点的边表的第一条边;
    edge2:指向以该顶点为终点的边表的第一条边。
    在这里插入图片描述

(2)边表结点结构与无向图的邻接多重表相同,但ilink指向以Vi为始点的下一条边;jlink指向以Vj为终点的下一条边。
在这里插入图片描述

练习:
在这里插入图片描述
在这里插入图片描述

三、基于邻接表表示的Graph结构

四、图的遍历

从图的任一顶点出发沿着边访问图的每个顶点恰好一次。

  1. 两种遍历方法
    (1)宽度优先遍历
    先访问出发顶点(第1层),然后访问与出发顶点相邻的所有顶点(第2层),接着访问与第2层顶点相邻的所有未被访问的顶点(第3层),……,依此类推。

练习:
在这里插入图片描述
宽度优先次序:ABCFDE

思考:尝试使用队列设计宽度优先遍历算法
分析:
队头<f, v>出队,若v未被访问,则访问v,<f, v>加入树,将与v相邻的未访问过的顶点依次入队。

教材算法思路:
a. 选一个未被访问过的顶点加入队列尾部;
b. while(队列不空)
删除队列头结点v;若v未被访问,则访问v,且将与v相邻的所有未访问过的顶点依次加入队列尾部。
c. 如果还有顶点没被访问过,则转a

宽度优先生成树:
宽度优先遍历中,将每次前进路过的结点和边记录下来,得到以出发点为根的树,称为宽度优先生成树。
宽度优先生成树林:
如果必须从多个结点出发才能遍历所有结点,则得到多棵生成树,称为宽度优先生成树林。

练习:
在这里插入图片描述

(2)深度优先遍历
在这里插入图片描述
深度优先次序:ABDCFE

思考:尝试使用栈实现深度优先?
分析:栈顶<f, v>出栈;若v未访问,则访问v, <f, v>加入树,将与v相邻的未访问过的顶点依次入栈。

教材算法思路:
a. 选一个未被访问过的顶点加入栈;
b. while(栈不空)
栈顶结点v出栈,若v未被访问,则访问v,且将与v相邻的所有未访问过的顶点依次入栈
c. 如果还有顶点没被访问过,则转a

深度优先生成树:
深度优先遍历中,将每次前进路过的结点和边记录下来,得到以出发点为根的树,称为深度优先生成树。
深度优先生成树林:
如果必须从多个结点出发才能遍历所有结点,则得到多棵生成树,称为深度优先生成树林。

练习:
在这里插入图片描述
在这里插入图片描述

五、最小代价生成树

引例:顶点代表城市,边代表光缆,边的权值代表光缆成本。如何铺设光缆,使得城市之间可以通过光缆进行通信,且铺设成本最低?

  1. 什么是最小代价生成树?
    加权图中,生成树的边的权值之和最小的生成树称为最小代价生成树。

注:图的生成树不唯一

  1. 跨U和V-U的最小边一定在最小生成树里
    在这里插入图片描述
    基于该定理,设计一个最小生成树算法。

  2. Prim算法
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    Prim算法的时间复杂度O(n^2)

  3. kruskal算法
    在这里插入图片描述
    练习:
    在这里插入图片描述

六、单源最短路径问题

定义:给定单个源点s,求s到其它各顶点的最短路径。
在这里插入图片描述
注意:s到i的最短路径上i的前面是j,那么s到j的最短路径加上<j,i>是s到i的最短路径。

思考:如何存储最短路径?
使用Dist数组:Dist[i].length = s到顶点i的最短距离,Dist[i].pre = 最短路径上顶点i的前一个顶点。
在这里插入图片描述
将顶点集分成A、B两组,A中的顶点已经确定从源到该顶点的最短路径,B中顶点尚未确定从源到该顶点的最短路径。设V0为源点,初始时A={V0}, B = V \ A.
在这里插入图片描述
给A和B中的顶点v定义距离值,记为v.length。对于A中的顶点v,v.length为从源到v的最短路径长;对于B中的顶点v, v.length为只允许以A中顶点为中间点的从源到v最短路径长。

在这里插入图片描述
B中距离值最小的顶点Vm, 其距离值就是从源到该顶点的最短路径长度。
在这里插入图片描述
Dijkstra算法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Dijkstra算法的时间复杂度是O(n^2)

七、每队顶点间最短路径问题

计算每队顶点之间的最短路径
方法1. 以网格中的每个顶点为源点,分别调用Dijkstra(),时间复杂性为O(n^3).
方法2. Floyd算法,时间复杂性是O(n^3)

例如:
在这里插入图片描述
思考:如何保存这些结果?
在这里插入图片描述
Floyd算法:
假设n个顶点{V0, V1, ……, Vn-1}, 边的权值非负,adj为相邻矩阵。
算法的结果保存在矩阵D和矩阵path中:
在这里插入图片描述

八、有向无回路图DAG

引例:
在这里插入图片描述
大型的工程可以划分为多个工序,大多数工序与其他工序相关联,即某些工序必须等到其它一些工序完成后才能开始。DAG是描述这类问题的有效工具。

两种DAG:
(1)AOV:顶点表示活动
(2)AOE:边表示活动

一、AOV网

  1. 什么是AOV网?
    用顶点表示活动,边表示活动间的先后关系。活动v1是活动v2的前提,当且仅当AOV网中v1是v2的前驱。
    在这里插入图片描述
  2. AOV网的拓扑排序
    对AOV网 G=<V,E>的顶点进行拓扑排序–把所有顶点排成一个序列V1, V2, ……,Vn,使得该序列满足:若<Vi, Vj>是G的边,则序列中Vi位于Vj之前。这个序列称为G的一个拓扑排序。

拓扑排序算法:
(1)从图中选择一个入度为0的顶点并输出;
(2)从图中删除此顶点及其所有的出边;
(3)重复1和2, 知道输出图的全部顶点。如果不能输出图的全部顶点,说明图中有回路。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

结论:
(1) 通过拓扑排序,可以为AOV网上的活动安排合理的先后执行次序。
(2)拓扑序列通常不唯一
(3)DAG图存在拓扑序列,不存在拓扑序列的有向图存在回路。

二、AOE网
用边表示活动,顶点表示活动的开始和结束(事件),边上的权表示活动所需的时间长度。活动e1是活动e2的前提,当且仅当AOE网中e1的终点是e2的起点。
在这里插入图片描述

  1. 顶点事件的发生?
    只有当顶点入边上的活动全部结束后,顶点事件才可以发生;只有当顶点事件发生后,顶点出边上的活动才可以启动。
    在这里插入图片描述

  2. 完成工程的最短时间?
    表示工程的AOE网有一个入度为0的顶点,称为源点,代表工程的始点,有一个出度为0的顶点,称为汇点,代表工程的终点。完成工程的最短时间为从源点到汇点的最长路径长度
    关键路径:AOE网从源点到汇点的最长路径称为关键路径。
    完成工程的最短时间为关键路径长度。

  3. 最早发生时间?
    假设AOE网的顶点集为{V1, V2, ……, Vn},V1为源点(始点),Vn为汇点(终点)。
    事件Vj的最早发生时间e(j):从源点到Vj的最长路径长。
    在这里插入图片描述

  4. 最晚发生时间
    假设AOE网的顶点集为{V1, V2, ……, Vn},V1为源点(始点),Vn为汇点(终点)。
    在不耽误工程进度的前提下,事件vi最晚发生时间I(i):关键路径长减去从Vi到汇点的最长路径长。
    在这里插入图片描述

  5. 关键事件
    最早和最晚发生时间相等的时间为关键事件。
    在这里插入图片描述

  6. 关键活动
    活动ai=<Vj, Vk>的最早启动时间ae(i)=e(j)最晚启动时间aI(i) = I(k)-t(j, k)
    最早和最晚启动时间相等的活动为关键活动。
    在这里插入图片描述
    求关键活动的算法
    (1)对顶点进行拓扑排序
    (2)按顶点的拓扑次序从前往后,计算每个顶点Vi的最早发生时间e(i)
    (3)按顶点的拓扑次序从后往前,计算每个顶点Vk的最晚发生时间l(k)
    (4)若l(k)-t(j, k) = e(j),则<Vj, Vk>是关键活动。

注意:
某路径是关键路径的充要条件是其上的每个活动是关键活动(其上每个顶点是关键事件)

总结:
在这里插入图片描述

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值