【问题标题】:Return all topological sort orderings in a graph using Kahn's algorithm?使用卡恩算法返回图中的所有拓扑排序顺序?
【发布时间】:2019-08-07 15:30:39
【问题描述】:

我正在尝试解决一种情况,即我实现了卡恩算法以在图中查找并返回一个拓扑排序。但是,我想尝试实现它以返回所有拓扑顺序。例如,如果一个图有 4 个节点,并且具有以下边:

(1 2)
(1 3)
(2 3)
(2 4)

它将返回以下 2 个可能的拓扑顺序:

[1 2 3 4] 
[1 2 4 3]

无论如何我可以用我的以下代码来做这件事:

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) 


    # The function to do Topological Sort.  
    def topologicalSort(self): 

        # Create a vector to store indegrees of all 
        # vertices. Initialize all indegrees as 0. 
        in_degree = [0]*(self.V) 

        # Traverse adjacency lists to fill indegrees of 
           # vertices.  This step takes O(V+E) time 
        for i in self.graph: 
            for j in self.graph[i]: 
                in_degree[j] += 1

        # Create an queue and enqueue all vertices with 
        # indegree 0 
        queue = [] 
        for i in range(self.V): 
            if in_degree[i] == 0: 
                queue.append(i) 

        #Initialize count of visited vertices 
        cnt = 0

        # Create a vector to store result (A topological 
        # ordering of the vertices) 
        top_order = [] 

        # One by one dequeue vertices from queue and enqueue 
        # adjacents if indegree of adjacent becomes 0 
        while queue: 

            # Extract front of queue (or perform dequeue) 
            # and add it to topological order 
            u = queue.pop(0) 
            top_order.append(u) 

            # Iterate through all neighbouring nodes 
            # of dequeued node u and decrease their in-degree 
            # by 1 
            for i in self.graph[u]: 
                in_degree[i] -= 1
                # If in-degree becomes zero, add it to queue 
                if in_degree[i] == 0: 
                    queue.append(i) 

            cnt += 1

        # Check if there was a cycle 
        if cnt != self.V: 
            print "There exists a cycle in the graph"
        else : 
            #Print topological order 
            print top_order 

 #Test scenario
 g = Graph(4);
 g.addEdge(1, 2);
 g.addEdge(1, 2);
 g.addEdge(2, 3);
 g.addEdge(2, 4);

 g.topologicalSort()

【问题讨论】:

  • 你需要所有可能的拓扑顺序还是 1 就足够了?此代码仅返回 1 并稍作修改

标签: python-3.x graph topological-sort


【解决方案1】:

您的问题陈述与 NetworkX all topo sorts 函数匹配。

如果你只想要结果,我建议按原样调用他们的函数。

如果您想破解一个实现,他们的源代码可能会通知您自己的。在这种情况下,您可能会选择从 Kahn 算法切换到他们引用的 Knuth 算法。

【讨论】:

    【解决方案2】:

    注意图节点索引以0开头:

    g.addEdge(1, 2);  # replace with 0, 1 and so on
    

    通过这个修改,这个算法只返回一个拓扑排序,而图可以有更多的排序,因为我们总是只从队列中选择第一个项目。要获得所有排序,您可以使用此修改后的代码:

    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)
    
    
        # The function to do Topological Sort.  
        def topologicalSort(self): 
    
            # Create a vector to store indegrees of all 
            # vertices. Initialize all indegrees as 0. 
            in_degree = [0] * self.V
    
            # Traverse adjacency lists to fill indegrees of 
            # vertices.  This step takes O(V+E) time 
            for i in self.graph:
                for j in self.graph[i]:
                    in_degree[j] += 1
    
            # Create an queue and enqueue all vertices with 
            # indegree 0 
            queue = []
            for i in range(self.V):
                if in_degree[i] == 0:
                    queue.append(i)
    
            self.process_queue(queue[:], in_degree[:], [], 0)
    
        def process_queue(self, queue, in_degree, top_order, cnt):
            if queue:
    
                # We have multiple possible next nodes, generate all possbile variations
                for u in queue:
    
                    # create temp copies for passing to process_queue
                    curr_top_order = top_order + [u]
                    curr_in_degree = in_degree[:]
                    curr_queue = queue[:]
                    curr_queue.remove(u)
    
                    # Iterate through all neighbouring nodes 
                    # of dequeued node u and decrease their in-degree 
                    # by 1 
                    for i in self.graph[u]:
                        curr_in_degree[i] -= 1
                        # If in-degree becomes zero, add it to queue 
                        if curr_in_degree[i] == 0:
                            curr_queue.append(i)
    
                    self.process_queue(curr_queue, curr_in_degree, curr_top_order, cnt + 1)  # continue recursive
    
            elif cnt != self.V:
                print("There exists a cycle in the graph")
            else:
                #Print topological order 
                print(top_order)
    
    
    g = Graph(4);
    g.addEdge(0, 1);
    g.addEdge(0, 2);
    g.addEdge(1, 2);
    g.addEdge(1, 3);
    
    g.topologicalSort()
    

    输出:

    [0, 1, 2, 3]

    [0, 1, 3, 2]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-27
      • 1970-01-01
      • 1970-01-01
      • 2019-03-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多