Python 拓扑排序

8 投票
5 回答
21946 浏览
提问于 2025-04-17 16:51

我写了一个非递归的深度优先搜索(DFS)解决方案,但我不知道怎么改才能实现拓扑排序:

def dfs(graph,start):
    path = []
    stack = [start]    
    while stack != []: 
        v = stack.pop()
        if v not in path: path.append(v)
        for w in reversed(graph[v]): 
            if w not in path and not w in stack:
                stack.append(w) 
    return path

有没有什么想法可以帮我修改一下?

用递归版本我可以很容易地得到排序:

def dfs_rec(graph,start,path):
    path = path + [start]
    for edge in graph[start]: 
        if edge not in path:
            path = dfs_rec(graph, edge,path)
    print start
    return path

输入:

>>> graph = {
        1: [2, 3],
        2: [4, 5, 6],
        3: [4,6],
        4: [5,6],
        5: [6],
        6: []
    }
>>> dfs_rec(graph,1,[])
6
5
4
2
3
1
[1, 2, 4, 5, 6, 3]
>>> dfs(graph,1)
[1, 2, 4, 5, 6, 3]
>>> graph = {
        1: [3],
        3: [5,6],
        5: [4],
        4: [7],
        7: [],
        6: []
    }
>>> print dfs_rec(graph,1,[])
7
4
5
6
3
1
[1, 3, 5, 4, 7, 6]
>>> print dfs(graph,1)
[1, 3, 5, 4, 7, 6]

所以我也需要在非递归的版本中得到这个排序。

非递归解决方案:

我觉得这也可能是解决方案,如果我错了请告诉我。

def dfs(graph,start):
    path = []
    stack = [start]
    label = len(graph)
    result = {}  
    while stack != []:
        #this for loop could be done in other ways also
        for element in stack:
            if element not in result:
                result[element] = label
                label = label - 1

        v = stack.pop()
        if v not in path: path.append(v)
        for w in reversed(graph[v]): 
            if w not in path and not w in stack:
                stack.append(w) 

    result = {v:k for k, v in result.items()}
    return path,result

输入:

graph = { 1: [3], 3:[5,6] , 5:[4] , 4:[7], 7:[],6:[]}
print dfs(graph,1) 

输出:

([1, 3, 5, 4, 7, 6], {1: 7, 2: 4, 3: 5, 4: 6, 5: 3, 6: 1})

        1
       / 
      3
     /\
    5  6
   /
  4
 /
7    

5 个回答

0
    #this algorithm gives the logic of topological sorting..if u want to run this 
    #give adjacency mat of your choice and this algorithm works on graph elements ranging from 0 to n 

    a=[[0,0,1,0,0,0],[0,0,1,0,0,0],[0,0,0,1,1,0],[0,0,0,0,1,0],[0,0,0,0,0,0],[0,0,1,0,0,0]]
    vis=[0 for i in range(0,len(a))]
    s=[]

    orderstack=[]#stores the reverse order of topological sorted elements

    def dfs_for_topological_sorting(a,vis,i):

        vis[i]=1
        x=0
        for j in range(0,len(a[0])):
            if(a[i][j]==1 and vis[j]==0):
                x=1
                s.append(j)
                #print(s)
                dfs_for_topological_sorting(a,vis,j)
        if(x==0 and len(s)!=0):

            orderstack.append(s[len(s)-1])
        if(len(s)>0):
            dfs_for_topological_sorting(a,vis,s.pop())

    for i in range(0,len(a)):
        if(i not in orderstack):
            s.append(i)
            dfs_for_topological_sorting(a,vis,i)
    print(orderstack[len(orderstack)-1::-1])        

当然可以!请把你想要翻译的内容发给我,我会帮你用简单易懂的语言解释清楚。

1

在编程中,有时候我们需要处理一些数据,比如从一个地方获取数据,然后在程序中使用这些数据。这个过程就像是从冰箱里拿食材,然后用这些食材做饭一样。

当我们获取数据时,可能会遇到一些问题,比如数据格式不对,或者数据缺失。这就像是你打开冰箱,发现里面的食材不够,或者有些食材过期了。

为了避免这些问题,我们可以在获取数据之前,先检查一下数据的状态。这就像是你在做饭之前,先检查一下冰箱里的食材是否新鲜,是否足够。

如果数据有问题,我们可以选择不使用这些数据,或者尝试修复它们。就像是你发现冰箱里的食材不新鲜,就去超市买新的食材来替代。

总之,处理数据就像做饭一样,需要仔细检查和准备,才能做出美味的菜肴。

from collections import defaultdict, deque


class Graph:
    def __init__(self, directed=False, nodes=None, edges=None):
        self.graph = defaultdict(list)
        self.directed = directed
        self.add_nodes(nodes)
        self.add_edges(edges)

    @property
    def nodes(self):
        if not self.directed:
            return list(self.graph.keys())
        elif self.directed:
            nodes = set()
            nodes.update(self.graph.keys())
            for node in self.graph.keys():
                for neighbor in self.graph[node]:
                    nodes.add(neighbor)
            return list(nodes)

    def add_node(self, node):
        if node not in self.nodes:
            self.graph[node] = list()

    def add_nodes(self, nodes):
        if nodes is None:
            return None
        for node in nodes:
            self.add_node(node)

    @property
    def edges(self):
        edges = list()
        for source, neighbors in self.graph.items():
            for neighbor in neighbors:
                edges.append((source, neighbor))
        return edges

    def add_edge(self, edge):
        node1, node2 = edge
        self.graph[node1].append(node2)
        if not self.directed:
            self.graph[node2].append(node1)

    def add_edges(self, edges):
        if edges is None:
            return None
        for edge in edges:
            self.add_edge(edge)

    def topological_util(self, node, visited, label):
        visited[node] = True
        for edge in self.graph[node]:
            if not visited[edge]:
                self.topological_util(edge, visited, label)
        label.appendleft(node)

    def topological_sort(self):
        visited = dict.fromkeys(self.nodes, False)
        # store all nodes in topological order, the index is the position
        label = deque()
        for node in self.nodes:
            if not visited[node]:
                self.topological_util(node, visited, label)
        return label
7

顺便说一下,这里有一些我写的代码,用于实现一种非递归的拓扑排序。

from collections import defaultdict, namedtuple
from itertools import islice

Results = namedtuple('Results', ['sorted', 'cyclic'])

def topological_sort(dependency_pairs):
    'Sort values subject to dependency constraints'
    num_heads = defaultdict(int)   # num arrows pointing in
    tails = defaultdict(list)      # list of arrows going out
    heads = []                     # unique list of heads in order first seen
    for h, t in dependency_pairs:
        num_heads[t] += 1
        if h in tails:
            tails[h].append(t)
        else:
            tails[h] = [t]
            heads.append(h)

    ordered = [h for h in heads if h not in num_heads]
    for h in ordered:
        for t in tails[h]:
            num_heads[t] -= 1
            if not num_heads[t]:
                ordered.append(t)
    cyclic = [n for n, heads in num_heads.items() if heads]
    return Results(ordered, cyclic)

if __name__ == '__main__':
    print( topological_sort('aa'.split()) )
    print( topological_sort('ah bg cf ch di ed fb fg hd he ib'.split()) )

撰写回答