Lecture 5. 图
图的表示
对于图 ,其中 是点集, 是边集。
对于无向图和有向图,都可以用若干 邻接表(adjacency list) 或 邻接矩阵(adjacency matrix) 表示。
- 对于 稀疏(sparse) 图(),通常选择邻接表
- 对于 稠密(dense) 图(),或需要快速查询两点之间是否有边,则用邻接矩阵
邻接表
是 个链表构成的数组。 包含了满足 的所有节点 。
- 若 是有向图,那么所有链表的长度总和,就是
- 若 是无向图,那么所有链表的长度总和,就是
邻接表的缺点是无法快速查找图中是否存在一条边 。
邻接矩阵
邻接矩阵 是一个 的零一矩阵,行列标号从 到 :$$a_{i,j}=\begin{cases}1 & (i,j) \in E \ 0 & (i,j) \not\in E\end{cases}$$,因此其占用的空间是 级别的。
边带权图
对于边带权的图(有一个函数 ),只需要在邻接表里面把这个边权额外存储进去,或者把邻接矩阵的零一改成实数。
BFS
Dijkstra 最短路算法和 Prim 最小生成树算法都有用到类似 BFS 的思想。
对于图 ,指定起点 ,BFS 可以计算出 到其他任意节点的距离。BFS 在遍历到距离起点 的节点之前,一定会先遍历到距离 的节点。
不论是有向图还是无向图,在 广度优先树(breadth-first tree) 当中,节点 到 的简单路径,都对应着原图当中 到 的最短路径。
伪代码
- 表示节点 的状态,黑白灰三种。白表示未处理,灰表示入队,黑表示处理完毕
- 表示节点 距离起点的距离
- 表示节点 在广度优先树当中的前驱节点

效率分析
- 初始化需要 时间。
- 每个节点入队出队一次,每次入队出队需要 时间,总共需要 时间
- 需要遍历邻接表。邻接表长度 ,需要 时间
- 故总时间复杂度
DFS
伪代码
- 表示节点 的状态,黑白灰三种。白表示未处理,灰表示正在处理其子树,黑表示处理完毕
- 表示开始处理的时间戳,是 discovered 的缩写
- 表示处理完毕后的时间戳,是 finished 的缩写

效率分析
- 初始化需要 的时间
- 每个节点记录 和 ,总共需要 时间
- 需要遍历邻接表。邻接表长度 ,需要 时间
- 故总时间复杂度
括号化定理
在无向图或有向图当中,节点 , 有以下可能的关系
- 深度优先森林中, 不是 的后代, 也不是 的后代: 与 完全分离
- 深度优先树中, 是 的后代,
- 深度优先树中, 是 的后代,
边的分类
一条边 有以下四种分类:
- 树边 tree edges,表示 是由 直接发现的
- 后向边 back edges,表示深度优先树中 的祖先是 。有向图的自环也算后向边
- 前向边 forward edges,表示深度优先树中 的后代是
- 横叉边 cross edges,表示所有其他类型的边