拓扑排序

对一个有向无环图 (Directed Acyclic Graph 简称 DAG) G 进行拓扑排序,是将 G 中所有顶点排成一个线性序列,使得图中任意一对顶点 u 和 v,若边 (u,v) ∈ E(G),则 u 在线性序列中出现在 v 之前。

拓扑排序对应施工的流程图具有特别重要的作用,它可以决定哪些子工程必须要先执行,哪些子工程要在某些工程执行后才可以执行。为了形象地反映出整个工程中各个子工程(活动)之间的先后关系,可用一个有向图来表示,图中的顶点代表活动(子工程),图中的有向边代表活动的先后关系,即有向边的起点的活动是终点活动的前序活动,只有当起点活动完成之后,其终点活动才能进行。通常,我们把这种顶点表示活动、边表示活动间先后关系的有向图称做顶点活动网(Activity On Vertex network),简称 AOV 网。
一个 AOV 网应该是一个有向无环图,即不应该带有回路,因为若带有回路,则回路上的所有活动都无法进行(对于数据流来说就是死循环)。在 AOV 网中,若不存在回路,则所有活动可排列成一个线性序列,使得每个活动的所有前驱活动都排在该活动的前面,我们把此序列叫做拓扑序列 (Topological order),由 AOV 网构造拓扑序列的过程叫做拓扑排序 (Topological sorting)。AOV 网的拓扑序列不是唯一的,满足上述定义的任一线性序列都称作它的拓扑序列。

在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序:

  • 每个顶点出现且只出现一次;
  • 若 A 在序列中排在 B 的前面,则在图中不存在从 B 到 A 的路径。

拓扑排序算法

任何无回路的顶点活动网(AOV网)G 都可以做出拓扑序列:

  • 从 G 中选出一个入度为 0 的顶点作为序列的下一顶点。
  • 从 G 网中删除所选顶点及其所有的出边。

反复执行上面两个步骤,直到已经选出了图中的所有顶点,或者再也找不到入度为 0 的顶点时算法结束。
如果剩下入度非 0 的顶点,就说明 G 中有回路,不存在拓扑排序。
存在回路,意味着某些活动的开始要以其自己的完成作为先决条件,这种现象成为活动之间的死锁。因此可以说拓扑排序算法是为了做出满足制约关系的工作安排。

from collections import defaultdict 
 
class Graph: 
    def __init__(self,vertices): 
        self.graph = defaultdict(list) 
        self.V = vertices
  
    def addEdge(self,u,v): 
        self.graph[u].append(v) 
  
    def topologicalSortUtil(self,v,visited,stack):   
        visited[v] = True       
        for i in self.graph[v]: 
            if visited[i] == False: 
                self.topologicalSortUtil(i,visited,stack) 
  
        stack.insert(0,v) 
  
    def topologicalSort(self): 
        visited = [False]*self.V 
        stack =[] 
  
        for i in range(self.V): 
            if visited[i] == False: 
                self.topologicalSortUtil(i,visited,stack) 
  
        print (stack) 
  
g = Graph(6) 
g.addEdge(5, 2); 
g.addEdge(5, 0); 
g.addEdge(4, 0); 
g.addEdge(4, 1); 
g.addEdge(2, 3); 
g.addEdge(3, 1); 
print(g.graph)
# defaultdict(<class 'list'>, {5: [2, 0], 4: [0, 1], 2: [3], 3: [1]})

print ("拓扑排序结果:")
g.topologicalSort()
# [5, 4, 2, 3, 1, 0]

拓扑排序:从给定的图的所有边中「提取出该图的某一个拓扑序列」的过程,拓扑序列是一条满足图中有向边前后关系的序列,任一有向边起点在序列中一定早于终点出现。如果图中有环,则无法提取出拓扑序列。所以拓扑排序的一个重要应用是在给定的有向图中判定是否存在环路。