【问题标题】:How to topological sort a sub/nested graph?如何对子/嵌套图进行拓扑排序?
【发布时间】:2026-01-26 13:15:01
【问题描述】:

我创建了一个轻量级图形库,它有 3 个对象(Vertex、Edge、Graph)和 1 个函数(topo_sort),如下所示:

class DAGError(Exception): pass

def topo_sort(graph):
    sorted_list = []
    def visit(vertex):
        nonlocal sorted_list
        if vertex.idle:
            raise DAGError('Graph has at least one cycle.')
        if not vertex.done:
            vertex.idle = True
            for neighbor in vertex.vertices():
                visit(neighbor)
            vertex.done = True
            vertex.idle = False
            sorted_list.insert(0, vertex)
    queue = [vertex for vertex in graph.vertices() if not vertex.done]
    while queue:
        visit(queue.pop(0))
    return iter(sorted_list)

如果我有一个扁平的 DAG,这可以正常工作。但我想要实现的是在我的主图中添加子图(或嵌套图),正如您在我绘制的这张插图中看到的那样:

这仍然是一个 DAG,所以如果我对此运行我的函数,正常 topo_sort 输出将是这样的:

V0, V3, V1, V5, V4, V8, V7, V12, V11, V13, V14, V2, V6, V10, V9, V15, V17, V16

但是我的首选输出是当子图所依赖的所有顶点在处理子图的顶点之前“处理” - 所以它应该是这样的:

V0, V1, V8,        # vertices of maingraph
V3, V5, V4, V12    # vertices of subgraph_0
V7, V11, V13,      # vertices of subgraph_1
V14                # vertex   of subgraph_0
V2                 # vertex   of maingraph
V6, V10, V9, V15   # vertices of subgraph_2
V16, V17           # vertices of maingraph

但我找不到任何资源:

  • 如何将图中的顶点“标记”或“存储”为子图的一部分?
  • 如何根据顶点的子图依赖关系对顶点进行排序(如上例)?
  • 如何将子图作为独立图获取或处理?

我希望我能足够详细地解释我的问题——尽管如果有什么遗漏,请告诉我,我会用遗漏的部分来扩展我的问题。

提前致谢!


编辑:

我发现了这个(Boost Graph Library, BGL),它看起来解决了我遇到的一个非常相似的(或完全相同?)问题,虽然我不熟悉 C++,所以我不'不明白它是如何工作的以及它到底在做什么——但我把它放在这里,也许有人会觉得回答我的问题很有帮助..


编辑 2:

我也接受伪代码,而不仅仅是 python!当然,如果现有的 python 库知道这一点,我对此很感兴趣,但是,我不想使用像 graph-tools 这样庞大的库——这就是我创建自己的库的原因,所以我更喜欢实现比库。

【问题讨论】:

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


    【解决方案1】:

    对你来说可能有点晚了,但对于其他有类似问题的人来说:

    如何将图中的顶点“标记”或“存储”为子图的一部分?

    为什么不给顶点对象一个属性subgraph,它包含一个整数或一个字符串标记顶点所属的子图? (如果您想使用 NetworkX,请使用node attribute dictionary) 这样,您可以在排序算法中检查此子图属性。

    如何根据顶点的子图依赖关系对顶点进行排序(如上面的示例)?

    我不是拓扑排序方面的专家,但假设每个顶点“知道”它所属的子图,这就是我想出的(使用 NetworkX,但您可以轻松实现我在您自己的库中使用的部分):下面的代码收集了您描述的所有“依赖项”(所有需要在当前顶点之前出现的顶点)。您可以使用此信息来修改您的 topol_sort() 函数,使其仅在其依赖项中的所有顶点都未在列表中时才将当前顶点附加到列表中。

    import networkx as nx
    
    # define the graph and the subgraphs suitable for NetworkX
    G = ...
    subgraphs = ...
    
    for subgraph in subgraphs:
        # find all vertices that the current subgraph depends on
        dependencies = set()
        for vertex in subgraph:
            anc = nx.ancestors(G, vertex) # anc is the set of all vertices having a path to 'vertex'
            dependencies.union(anc)
        dependencies -= subgraph.nodes()
        # store these dependencies under every vertex of the current subgraph
        for vertex in subgraph:
            G[vertex].node['depends'] = dependencies
    
    # run modified topological sorting
    topo_sort_mod(G)
    

    如何将子图作为独立图获取或处理?

    我不确定你到底想要什么。也许this 有帮助(同样,使用 NetworkX),尤其是这部分:

    要使用自己的边/节点属性副本创建子图,请使用:nx.Graph(G.subgraph(nbunch))

    如果边缘属性是容器,可以使用以下方法获得深拷贝:G.subgraph(nbunch).copy()

    我希望这对任何人都有帮助...... :)

    【讨论】:

      【解决方案2】:

      阅读您关于 Graph-tools 的声明,但仍然不确定您是否喜欢使用库来完成某项工作,或者您想了解如何自己编写它。

      也许你在看

      General Samples
      [http://networkx.github.io/examples.html][1]
      
      DAG Example
      [http://networkx.lanl.gov/archive/networkx-1.6/_modules/networkx/algorithms/dag.html][2]
      

      看看它是否能帮助你解决问题?

      【讨论】:

      • 谢谢@Peter——我已经知道networkx,但我重新检查了它,尽管我读了all the articles mentioning the word 'subgraph',但似乎networkx没有我正在寻找的功能对于(或者至少,我不知道)——虽然它有一个subgraph() 方法,但它只重新引用了图形的一部分,这不会影响排序算法。无论如何,再次感谢,但这些链接都没有帮助..(顺便说一句,我更喜欢自己理解和实施)
      最近更新 更多