拓扑排序 是将一个有向无环图中的每个节点按照依赖关系进行排序。比如图 G G G存在边 < u , v > <u,v> <u,v> 代表 v v v的依赖 u u u, 那么在拓扑排序中,节点 u u u一定在 v v v的前面。
从另一个角度看,拓扑排序是一种图遍历,具有两个性质:
拓扑排序能够在 O ( V + E ) O(V+E) O(V+E)的线性时间内完成,分为两种算法-Kahn算法和深度优先搜索
这个图有很多有效的拓扑排序,包括:
视觉从左到右,从上到下:
5, 7, 3, 11, 8, 2, 9, 10
最小编号的可用顶点优先:
3, 5, 7, 8, 11, 2, 9, 10
按入边邻居的字典顺序:
3, 5, 7, 8, 11, 2, 10, 9
最少边数优先:
5, 7, 3, 8, 11, 2, 10, 9
最大编号的可用顶点优先:
7, 5, 11, 3, 10, 8, 9, 2
尝试从上到下,从左到右:
5, 7, 11, 2, 3, 8, 9, 10
任意顺序:
3, 7, 8, 5, 11, 10, 2, 9
L ← Empty list that will contain the sorted elements
S ← Set of all nodes with no incoming edge
while S is not empty do
remove a node n from S
add n to L
for each node m with an edge e from n to m do
remove edge e from the graph
if m has no other incoming edges then
insert m into S
if graph has edges then
return error (graph has at least one cycle)
else
return L (a topologically sorted order)
这个算法的思想是:
3,5,7
都是起始节点。算法依据的原理是什么?
无环图的正常遍历情况是这样的:
黄色代表集合S中的节点
有环图的情况:
如果图G中有环,遍历至环路中任一节点,因为无法在环路中,找到任何一个开始节点进入环路,导致S为空,算法中止。
L ← Empty list that will contain the sorted nodes
while exists nodes without a permanent mark do
select an unmarked node n
visit(n)
function visit(node n)
if n has a permanent mark then
return
if n has a temporary mark then
stop (graph has at least one cycle)
mark n with a temporary mark
for each node m with an edge from n to m do
visit(m)
remove temporary mark from n
mark n with a permanent mark
add n to head of L
Kahn算法会破坏原来图的数据,而深度优先不会。深度优先算法采取的是标记方式探测环路。
注意到节点 n n n, 是添加到列表头部,因为是深度优先搜索,节点 n n n带永久标记代表从 n n n出发的能访问到的节点都被访问了,
即所有依赖节点 n n n的节点都已在列表里了。
环路情况: