6.1-1 图的基本概念
图的定义

有向图、无向图
没有箭头的那一段是弧尾,有箭头的那一段叫弧头。AE中A是弧尾,E是弧头。

简单图、多重图

顶点的度、入度、出度

顶点-顶点的关系描述
强连通就是正反都有路径,A和B是强联通的,A和E就不是强连通的

连通图、强连通图

子图
无向图

有向图(和上面无向图的定义相同)

连通分量(描述无向图的)
极大连通子图是子图,且连通,且包含尽可能多的顶点和边

强连通分量(描述有向图的)
有向图中的 极大强连通子图 称为有向图的 强连通分量(极大强连通子图是强连通分量)

生成树

生成森林

边的权、带权图/网
北京到上海的带权路径长度是200+600=800

几种特殊形态的图



n个顶点的连通图最少有n-1条边,如果在多一条边,一定有回路。
6.2-1 邻接矩阵法(数组实现的顺序存储,空间复杂度高,不适合存储稀疏图)
0表示不连接,1表示连接。
Vex数组中存储A,B,C,D,E,F,
然后在Edge中对应数组下标0,1,2,3,4,5,
这样我们表示AB这条边 就可以用Edge[0][1]=1来表示了。

因为Edge数组中只存0、1,且bool类型只占1个字节,比int类型占4个字节 占用的空间少,所以可以考虑使用bool类型表示边。
邻接矩阵存储 不带权 的图
下图中的(vi,vj)中的v是上图中的char型名为Vex的数组。


邻接矩阵存储 带权 图


邻接矩阵法的性能分析


邻接矩阵法的性质

矩阵相乘

从顶点1到顶点4的长度为2的路径的数目为1

6.2-2 邻接表法(顺序+链式存储)

无向图中:边会被链表使用两次,所以边结点的数量是2|E|,整体空间复杂度是O(|V|+2|E|).
无向图中度就是遍历对应结点的链表就行了。
有向图中:求出度容易,直接遍历对应结点的链表就行了,找 出边也容易,如果求入度、度、入边,那么需要遍历整个表才行。



6.2-3 十字链表、邻接多重表
十字链表(存储有向图)
十字链表法解决了有向图 找入边 不方便问题。
橙色连接了弧头相同的弧,绿色连接了弧尾相同的弧。


邻接多重表(存储无向图)
邻接矩阵、邻接表 存储无向图的缺点

邻接多重表 存储无向图

两个删除操作
删除一条边


删除一个顶点(同时也把与该顶点连接的边进行删除)


邻接矩阵、邻接表、十字链表、邻接多重表 总结

6.2-4 图的基本操作

Adjacent()


Neighbors()


InsertVertex()

DeleteVertex()

下图O(|E|)是 要遍历每一条边 来删除与 被删除结点 有关的边,如图中就是遍历每条边来删除与结点C有关的边。


AddEdge()

RemoveEdge()

FirstNeighbor()


NextNeighbor()

获取或设置权值
获取或设置权值 即 找到对应的边,然后获取或设置权值(获取和设置权值的时间复杂度是O(1) )。所以获取或设置权值的整体操作(包括找边和设置权值)和 只找边的时间复杂度相同。

6.3-1 图的广度优先遍历
广度优先遍历代码引入





算法存在的问题

广度优先算法(Breadth-First-Search,BFS算法)最终版


算法分析
空间复杂度
最坏情况,要一次把所有邻接点(即其余结点装入辅助队列),此时空间复杂度最高。

时间复杂度
算法时间开销主要是:访问各个顶点和查找每个顶点的邻接点。

广度优先生成树
标红,当某个顶点第一次被访问时是从哪条边过去的



广度优先生成森林
把广度优先生成树放在一起,就是广度优先生成森林。

6.3-2 图的深度优先遍历
图的深度优先遍历类似于树的先根遍历

图的深度优先遍历代码 引入







算法存在的问题(和广度优先存在的问题一样,无法处理非连通图,解决办法也一样)

深度优先遍历算法(Depth-First-Search)最终版

算法分析
空间复杂度

时间复杂度

深度优先遍历序列


深度优先生成树
标红,当某个顶点第一次被访问时是从哪条边过去的,把标红的边 和 结点单独拿出来,未标红的边去掉,就形成了深度优先生成树。


深度优先生成森林


图的遍历和图的连通性

下图,如果7仅仅能和邻接顶点6、3、8有路径而和其余顶点5、1、2、4没有路径,那么调用次数也是要多于1次的。

6.4-1 最小生成树
生成树是什么



最小生成树
带权、连通、无向


Prim算法
从p城出发







从农场出发

Kruskal算法





直到所有结点都连通,算法结束。
Prim算法和Kruskal算法对比

6.4-2 最短路径问题_BFS算法
最短路径问题介绍

BFS(广度优先求最短路径)
BFS算法求单源最短路径只适用于无权图,或所有边的权值都相同的图。
引入



BFS求无权图的单源最短路径的代码实现



按照最短路径的求解方法生成的树,高度一定是最小的。

6.4-3 最短路径问题_Dijkstra算法(迪杰斯特拉算法)
Dijkstra算法过程
初始化

第1轮



第2轮


第3轮


第4轮

如何使用数组信息?

算法的时间复杂度
每轮处理一个结点,( 花费时间O(n) )
每处理一个结点要遍历一遍dist数组查找最小的。( 花费时间O(n) )
时间复杂度 O(n²)

用于负权值带权图
首先选择还没确定最短路径的,且dist中最小的值 的 对应顶点设为true。

然后把V1设为true,算法结束。

通过算法得出的V1到V2的最短路径是7,而实际最短路径是5,说明Dijkstra算法不适用于有负权值的带权图。

6.4-4 最短路径问题_Floyd算法(弗洛伊德算法)

3个结点的弗洛伊德算法 演示
允许V0中转后,仅会更新以下一处数据。

允许V0、V1中转后,仅会更新以下一处数据。

允许V0、V1、V2中转后,仅会更新以下一处数据。



大于3个结点的弗洛伊德算法演示
不允许中转点

允许中转点V0


允许中转点V0、V1


允许中转点V0、V1、V2




允许中转点V0、V1、V2、V3



允许中转点V0、V1、V2、V3、V4


使用数组信息(A、path)找出最短路径

Floyd算法可以用于负权图

弗洛伊德算法不能解决的问题
比如从V0走到V1是-9,
如果V0->V1->V2->V0->V1是-9+(3+4±9)=-9±2=-11
这样每走一圈,V0到V1的最短路径就更小一次,没有尽头,无穷无尽。

最小路径总结

6.4-5 有向无环图描述表达式

将一棵树简化成有向无环图的过程



一道练习(答案是A.5)


6.4-6 拓扑排序
AOV网

拓扑排序引入





拓扑排序代码实现
代码实现过程











时间复杂度分析

逆拓扑排序
逆拓扑排序引入



逆拓扑排序的实现(DFS算法深度优先)



6.4-7 关键路径
概念引入
事件是一瞬间完成的。






求关键路径的步骤

1、求所有 事件 的最早发生时间

2、求所有 事件 的最迟发生时间

3、求所有 活动 的最早发生时间
每个活动的最早发生时间,就是这个活动的弧尾所连的这个事件的最早发生时间

4、求所有 活动 的最迟发生时间

5、求所有 活动 的时间余量d()

关键活动、关键路径的特性



本文深入探讨图的基本概念,包括有向图、无向图、连通图和强连通图。介绍了邻接矩阵和邻接表等存储结构,并分析其优缺点。接着讲解了图的遍历算法,如广度优先搜索(BFS)和深度优先搜索(DFS),以及它们在寻找最短路径中的应用。最后,讨论了最小生成树的Prim和Kruskal算法,以及Dijkstra算法解决单源最短路径问题。内容涵盖图的理论、算法实现及其在实际问题中的应用。

2125

被折叠的 条评论
为什么被折叠?



