📜  用于拓扑排序的Python程序

📅  最后修改于: 2022-05-13 01:56:56.410000             🧑  作者: Mango

用于拓扑排序的Python程序

有向无环图 (DAG) 的拓扑排序是顶点的线性排序,因此对于每个有向边 uv,顶点 u 在排序中位于 v 之前。如果图不是 DAG,则无法对图进行拓扑排序。
例如,下图的拓扑排序是“5 4 2 3 1 0”。一个图可以有多个拓扑排序。例如,下图的另一种拓扑排序是“4 5 2 3 1 0”。拓扑排序中的第一个顶点始终是入度为 0 的顶点(没有入边的顶点)。

图形

拓扑排序可以递归和非递归地实现。首先,我们展示更清晰的递归版本,然后为非递归版本提供分析。

递归拓扑排序

Python3
#Python program to print topological sorting of a DAG
from collections import defaultdict
 
#Class to represent a graph
class Graph:
    def __init__(self,vertices):
        self.graph = defaultdict(list) #dictionary containing adjacency List
        self.V = vertices #No. of vertices
 
    # function to add an edge to graph
    def addEdge(self,u,v):
        self.graph[u].append(v)
 
    # A recursive function used by topologicalSort
    def topologicalSortUtil(self,v,visited,stack):
 
        # Mark the current node as visited.
        visited[v] = True
 
        # Recur for all the vertices adjacent to this vertex
        for i in self.graph[v]:
            if visited[i] == False:
                self.topologicalSortUtil(i,visited,stack)
 
        # Push current vertex to stack which stores result
        stack.insert(0,v)
 
    # The function to do Topological Sort. It uses recursive
    # topologicalSortUtil()
    def topologicalSort(self):
        # Mark all the vertices as not visited
        visited = [False]*self.V
        stack =[]
 
        # Call the recursive helper function to store Topological
        # Sort starting from all vertices one by one
        for i in range(self.V):
            if visited[i] == False:
                self.topologicalSortUtil(i,visited,stack)
 
        # Print contents of 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 ("Following is a Topological Sort of the given graph")
g.topologicalSort()
#This code is contributed by Neelam Yadav


Python3
#Python program to print topological sorting of a DAG
from collections import defaultdict
 
#Class to represent a graph
class Graph:
    def __init__(self,vertices):
        self.graph = defaultdict(list) #dictionary containing adjacency List
        self.V = vertices #No. of vertices
 
    # function to add an edge to graph
    def addEdge(self,u,v):
        self.graph[u].append(v)
 
    # neighbors lazy generator given key
    def neighbor_gen(self,v):
        for k in self.graph[v]:
            yield k
     
    # non recursive topological sort
    def nonRecursiveTopologicalSortUtil(self, v, visited,stack):
         
        # working stack contains key and the corresponding current generator
        working_stack = [(v,self.neighbor_gen(v))]
         
        while len(working_stack) > 0:
            # get last element in stack
            v, gen = working_stack[-1]
            visited[v] = True
             
            # delete it from stack
            working_stack.pop()
             
            # run through neighbor generator until its empty
            continue_flag = True
            while continue_flag:
                next_neighbor = next(gen,None)
                 
                # if generator has returned all neighbors
                if next_neighbor is None:
                    continue_flag = False
                    # Save current key into the result stack
                    stack.append(v)
                    continue
                 
                # if new neighbor push current key and neighbor into stack
                if not(visited[next_neighbor]):
                    working_stack.append((v,gen))
                    working_stack.append((next_neighbor,self.neighbor_gen(next_neighbor)))
                    continue_flag = False
             
    # The function to do Topological Sort.
    def nonRecursiveTopologicalSort(self):
        # Mark all the vertices as not visited
        visited = [False]*self.V
         
        # result stack
        stack = []
 
        # Call the helper function to store Topological
        # Sort starting from all vertices one by one
        for i in range(self.V):
            if not(visited[i]):
                self.nonRecursiveTopologicalSortUtil(i, visited,stack)
         # Print contents of the stack in reverse
        print(stack[::-1])
 
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("The following is a Topological Sort of the given graph")
g.nonRecursiveTopologicalSort()
# The following code was based of Neelam Yadav's code and is modified by Suhail Alnahari


输出:

Following is a Topological Sort of the given graph
5 4 2 3 1 0

非递归拓扑排序

算法:

解决拓扑排序的方法是在处理完所有子节点后处理节点。每次处理一个节点时,都会将其压入堆栈以保存最终结果。这种非递归解决方案建立在 DFS 的相同概念之上,稍作调整即可在上文和本文中理解。然而,与递归解决方案在所有相邻元素都已被推入程序堆栈后保存堆栈中的节点顺序不同,此解决方案将程序堆栈替换为工作堆栈。如果一个节点有一个邻居没有被访问过,则当前节点和邻居被推到工作栈中进行处理,直到没有更多的邻居可以访问。
访问完所有节点后,剩下的是通过反向打印堆栈结果找到的最终结果。

Python3

#Python program to print topological sorting of a DAG
from collections import defaultdict
 
#Class to represent a graph
class Graph:
    def __init__(self,vertices):
        self.graph = defaultdict(list) #dictionary containing adjacency List
        self.V = vertices #No. of vertices
 
    # function to add an edge to graph
    def addEdge(self,u,v):
        self.graph[u].append(v)
 
    # neighbors lazy generator given key
    def neighbor_gen(self,v):
        for k in self.graph[v]:
            yield k
     
    # non recursive topological sort
    def nonRecursiveTopologicalSortUtil(self, v, visited,stack):
         
        # working stack contains key and the corresponding current generator
        working_stack = [(v,self.neighbor_gen(v))]
         
        while len(working_stack) > 0:
            # get last element in stack
            v, gen = working_stack[-1]
            visited[v] = True
             
            # delete it from stack
            working_stack.pop()
             
            # run through neighbor generator until its empty
            continue_flag = True
            while continue_flag:
                next_neighbor = next(gen,None)
                 
                # if generator has returned all neighbors
                if next_neighbor is None:
                    continue_flag = False
                    # Save current key into the result stack
                    stack.append(v)
                    continue
                 
                # if new neighbor push current key and neighbor into stack
                if not(visited[next_neighbor]):
                    working_stack.append((v,gen))
                    working_stack.append((next_neighbor,self.neighbor_gen(next_neighbor)))
                    continue_flag = False
             
    # The function to do Topological Sort.
    def nonRecursiveTopologicalSort(self):
        # Mark all the vertices as not visited
        visited = [False]*self.V
         
        # result stack
        stack = []
 
        # Call the helper function to store Topological
        # Sort starting from all vertices one by one
        for i in range(self.V):
            if not(visited[i]):
                self.nonRecursiveTopologicalSortUtil(i, visited,stack)
         # Print contents of the stack in reverse
        print(stack[::-1])
 
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("The following is a Topological Sort of the given graph")
g.nonRecursiveTopologicalSort()
# The following code was based of Neelam Yadav's code and is modified by Suhail Alnahari

输出:

Following is a Topological Sort of the given graph
5 4 2 3 1 0

复杂性分析:

  • 时间复杂度:O(V + E):上述算法是简单的 DFS,有一个工作栈和一个结果栈。与递归解决方案不同,递归深度在这里不是问题。
  • 辅助空间:O(V):使用的 2 个堆栈需要额外的空间。

有关详细信息,请参阅有关拓扑排序的完整文章。