编程语言
首页 > 编程语言> > 在python中看似简单的拓扑排序实现

在python中看似简单的拓扑排序实现

作者:互联网

here中提取我们得到了一个最小的迭代dfs例程,我把它称为最小,因为你很难进一步简化代码:

def iterative_dfs(graph, start, path=[]):
    q = [start]
    while q:
        v = q.pop(0)
        if v not in path:
            path = path + [v]
            q = graph[v] + q

    return path

graph = {
    'a': ['b', 'c'],
    'b': ['d'],
    'c': ['d'],
    'd': ['e'],
    'e': []
}
print(iterative_dfs(graph, 'a'))

这是我的问题,您如何将此例程转换为拓扑排序方法,其中例程也变为“最小”?我已经看过这个video并且这个想法很聪明,所以我想知道是否可以将相同的技巧应用到上面的代码中,因此topological_sort的最终结果也变得“最小”.

不要求拓扑排序的版本,这不是上述例程的微小修改,我已经看过很少.问题不是“我如何在python中实现拓扑排序”,而是找到上述代码的最小可能调整集成为topological_sort.

附加评论

在原文中,作者说:

A while ago, I read a graph implementation by Guido van Rossen that
was deceptively simple. Now, I insist on a pure python minimal system
with the least complexity. The idea is to be able to explore the
algorithm. Later, you can refine and optimize the code but you will
probably want to do this in a compiled language.

这个问题的目标不是优化iterative_dfs,而是提出从它派生的topology_sort的最小版本(仅仅是为了更多地了解图论算法).事实上,我想一个更普遍的问题可能是给定一组最小算法,{iterative_dfs,recursive_dfs,iterative_bfs,recursive_dfs},它们的topological_sort派生是什么?虽然这会使问题变得更长/更复杂,但是从iterative_dfs中找出topology_sort就足够了.

解决方法:

将DFS的迭代实现转换为拓扑排序并不容易,因为需要进行的更改在递归实现时更自然.但你仍然可以做到这一点,它只需要你实现自己的堆栈.

首先,这是一个稍微改进的代码版本(它更高效,而且不是更复杂):

def iterative_dfs_improved(graph, start):
    seen = set()  # efficient set to look up nodes in
    path = []     # there was no good reason for this to be an argument in your code
    q = [start]
    while q:
        v = q.pop()   # no reason not to pop from the end, where it's fast
        if v not in seen:
            seen.add(v)
            path.append(v)
            q.extend(graph[v]) # this will add the nodes in a slightly different order
                               # if you want the same order, use reversed(graph[v])

    return path

以下是我修改该代码以进行拓扑排序的方法:

def iterative_topological_sort(graph, start):
    seen = set()
    stack = []    # path variable is gone, stack and order are new
    order = []    # order will be in reverse order at first
    q = [start]
    while q:
        v = q.pop()
        if v not in seen:
            seen.add(v) # no need to append to path any more
            q.extend(graph[v])

            while stack and v not in graph[stack[-1]]: # new stuff here!
                order.append(stack.pop())
            stack.append(v)

    return stack + order[::-1]   # new return value!

我在这里评论“新东西”的部分是在向上移动时计算出顺序的部分.它检查找到的新节点是否是前一个节点(位于堆栈顶部)的子节点.如果没有,它会弹出堆栈顶部并将值添加到订单中.当我们正在进行DFS时,顺序将从反向拓扑顺序开始,从最后的值开始.我们在函数结束时将其反转,并将其与堆栈上的其余值连接(方便地按正确的顺序排列).

因为这段代码需要多次检查v不在图[stack [-1]]中,所以如果图形字典中的值是集合而不是列表,则效率会更高.图形通常不关心其边缘的保存顺序,因此进行此类更改不应导致大多数其他算法出现问题,尽管生成或更新图形的代码可能需要修复.如果您打算扩展图形代码以支持加权图形,那么最终可能会将列表更改为从节点到权重的字典映射,这对于此代码也是如此(字典查找是O(1)就像设置查找一样).或者,如果无法直接修改图形,我们可以构建自己需要的集合.

作为参考,这里是DFS的递归版本,并对其进行修改以进行拓扑排序.所需的修改确实非常小:

def recursive_dfs(graph, node):
    result = []
    seen = set()

    def recursive_helper(node):
        for neighbor in graph[node]:
            if neighbor not in seen:
                result.append(neighbor)     # this line will be replaced below
                seen.add(neighbor)
                recursive_helper(neighbor)

    recursive_helper(node)
    return result

def recursive_topological_sort(graph, node):
    result = []
    seen = set()

    def recursive_helper(node):
        for neighbor in graph[node]:
            if neighbor not in seen:
                seen.add(neighbor)
                recursive_helper(neighbor)
        result.insert(0, node)              # this line replaces the result.append line

    recursive_helper(node)
    return result

而已!一行被删除,类似的一行被添加到不同的位置.如果你关心性能,你应该在第二个辅助函数中执行result.append,并在顶级recursive_topological_sort函数中返回result [:: – 1].但是使用insert(0,…)是一个更小的变化.

值得注意的是,如果您需要整个图的拓扑顺序,则不需要指定起始节点.实际上,可能没有一个节点可以让您遍历整个图形,因此您可能需要进行多次遍历以获取所有内容.在迭代拓扑排序中实现这种情况的简单方法是将q初始化为列表(图形)(所有图形键的列表),而不是仅包含单个起始节点的列表.对于递归版本,将对recursive_helper(node)的调用替换为在图中的每个节点上调用辅助函数的循环(如果尚未看到).

标签:depth-first-search,python,algorithm,graph-theory,topological-sort
来源: https://codeday.me/bug/20190930/1836221.html