第四章 图(四) - 《算法》读书笔记
目录
第四章 图(四)
4.2 有向图
4.2.1 术语
定义:一幅有方向性的图(或有向图)是由一组顶点和一组有方向的边组成的,每条有方向的边都连接着有序的一对顶点。
- 我们称一条有向边由第一个顶点指出并指向第二个顶点
- 在一幅有向图中,一个顶点的出度为由该顶点指出的边的总数,入度为指向该顶点的边的总数
定义:在一幅有向图中,有向路径由一系列顶点组成,对于其中每个顶点都存在一条有向边从它指向序列中的下一个顶点。有向环为一条至少含有一条边且起点和终点相同的有向路径。简单有向环是一条(除了起点和终点必须相同之外)不含有重复的顶点和边的环。路径或者环的长度即为其中所包含的边数。
4.2.2 有向图的数据类型
- 有向图的API:
| public class | Digraph | |
|---|---|---|
| Digraph(int v) | 创建一幅含有V个顶点但没有边的有向图 | |
| Digraph(In in) | 从输入流in中读取一幅有向图 | |
| int | V() | 顶点总数 |
| int | E() | 边的总数 |
| void | addEdge(int v, int w) | 向有向图中添加一条边v->w |
| Iterable<Integer> | adj(int v) | 由v指出的边所连接的所有顶点 |
| Digraph | reverse() | 该图的反向图 |
| String | toString() | 对象的字符串表示 |
4.2.2.3 有向图取反
- API中添加了一个reverse()方法,它返回该有向图的一个副本,但将其中所有边的方向反转,这样就可以找出“指向”每个顶点的所有边
public Digraph reverse(){
Digraph R = new Digraph(V);
for(int v = 0; v < V; v++)
for(int w : adj(v))
R.addEdge(w, v);
return R;
}
4.2.3 有向图中的可达性
在有向图中,深度优先搜索标记由一个集合的顶点可达的所有顶点所需的时间与被标记的所有顶点的出度之和成正比。
4.2.4 环和有向无环图
4.2.4.1 调度问题
-
一种应用广泛的模型是给定一组任务,并安排它们的执行顺序,限制条件是这些任务的执行方法和起始时间
-
最终要的一条限制条件叫做优先级限制,它指明了哪些任务必须在哪些任务之前完成
-
优先级限制下的调度问题:给定一组需要完成的任务,以及一组关于任务完成的先后次序的优先级限制,在满足限制条件的前提下应该如何安排并完成所有任务?
-
拓扑排序:给定一幅有向图,将所有的顶点排序,使得所有的有向边均从排在前面的元素指向排在后面的元素(或者说明无法做到这一点)
4.2.4.2 有向图中的环
定义:有向无环图(DAG)就是一幅不含有有向环的有向图。
- 有向环检测:基于深度优先搜索,系统维护递归调用的栈,一旦我们找到了一条有向边v->w且w已经存在于栈中,就找到了一个环
private Stack<Integer> cycle;//有向环中的所有顶点(如如果存在)
private boolean[] onStack; //递归调用的栈上的所有顶点
private void dfs(Digraph G, int v){
onStack[v] = true;
marked[v] = true;
for(int w : G.adj(v))
if(this.hasCycle())
return;
else if(!marked[w]){
edgeTo[w] = v;
dfs(G, w);
} else if(onStack[w]){
cycle = new Stack<Integer>();
for(int x = v; x != w; x = edgeTo[x])
cycle.push(x);
cycle.push(w);
cycle.push(v);
}
onStack[v] = false;
}
- 在执行dfs(G, v)时,查找的是一条由起点到v的有向路径,要保存这条路径,算法中维护了一个由顶点索引的数组onStack[],以标记递归调用栈上的所有顶点(在调用dfs(G, v)时将onStack[v]设置为true,在调用结束时将其设置为false);同时使用了一个edgeTo[]数组,在找到有向环时返回环中的所有顶点。
4.2.4.2 顶点的深度优先次序与拓扑排序
当且仅当一幅有向图是无环图时,它才能进行拓扑排序。
- 如果将dfs()的参数顶点保存在一个数据结构中,遍历这个数据结构实际上就能访问图中的所有顶点,遍历的顺序取决于这个数据结构的性质以及是在递归调用之前还是之后进行保存
- 存在三种排序顺序:
- 前序pre:在递归调用之前将顶点加入队列
- 后序post:在递归调用之后将顶点加入队列
- 逆后序reversePost:在递归调用之后将顶点压入栈
一幅有向无环图的拓扑顺序即为所有顶点的逆后序排列。
使用深度优先搜索对有向无环图进行拓扑排序所需的时间和V+E成正比

浙公网安备 33010602011771号