【问题标题】:Graph traversal with Networkx (Python)使用 Networkx (Python) 进行图遍历
【发布时间】:2013-01-11 08:49:37
【问题描述】:

我正在使用 Networkx 来管理依赖关系图。 假设我有这个图表,每个字母代表一个服务器

>>> G = nx.Graph()
>>> G.add_edge("A","B")
>>> G.add_edge("A","H")
>>> G.add_edge("H","C")
>>> G.add_edge("B","C")
>>> G.add_edge("B","D")

           A
         /   \
       H       B
     /        /  \
   C         C     D 

所以在这里我们可以看到,在启动 A 之前,我们需要启动 H 和 B,启动 H 我们需要启动 C,然后启动 B,我们需要启动 C 和 D

稍微摆弄一下 Networkx,我发现我可以通过 dfs 遍历来实现这一点

print nx.dfs_successors(G,"A")
{A:[H,B], H:[C], B:[D] }

但我对这种方法有疑问。正如您所看到的,当树中有两个相同的字母时,Networkx 只选择将其中一个放在最终结构中(这是正确的)但我需要有完整的结构 如何强制 Networkx 添加到结构 B:[D,C] 中??

我想通过这样做来精确说明

>>> nx.dfs_successors(G,"B")
{'B': ['C', 'D']}

所以一切都是“内部”正确的,只是 dfs_successors 没有以我希望的方式显示它。

谢谢

【问题讨论】:

    标签: python networkx


    【解决方案1】:

    使用您的代码,您的图表并没有像您预期的那样出现。如果你这样做:

    import pylab as p
    import networkx as nx
    
    G = nx.Graph()
    G.add_edge("A","B")
    G.add_edge("A","H")
    G.add_edge("H","C")
    G.add_edge("B","C")
    G.add_edge("B","D")
    
    nx.draw(G)
    p.show()
    

    您将看到您的图表:

    这是由于G.add_edge("A", "B")的逻辑:

    1. 如果G没有id为“A”的节点,添加它。
    2. 如果G没有id为“B”的节点,添加它。
    3. 用新边将“A”连接到“B”。

    因此,您只创建了五个节点,而不是您图片中的六个。

    编辑 Networkx 可以将任何哈希值作为节点的值,并且在图中它使用 str(node) 来标记每个圆。所以我们可以简单地定义我们自己的 Node 类(您可能想将其称为 Server?)并为其提供所需的行为。

    import pylab as p
    import networkx as nx
    
    
    class Node(object):
        nodes = []
    
        def __init__(self, label):
            self._label = label
    
        def __str__(self):
            return self._label
    
    nodes = [Node(l) for l in ["A","B","C","C","D","H"]]
    edges = [(0,1),(0,5),(5,2),(1,3),(1,4)]
    
    G = nx.Graph()
    for i,j in edges:
        G.add_edge(nodes[i], nodes[j])
    
    nx.draw(G)
    p.show()
    

    给我们 所以你想要什么。

    【讨论】:

    • 感谢您绘制图表。这就是我“认为”Networkx 在我背后所做的事情。因此我的问题是:如何使用 Networkx 创建像我的示例中的树?通常对我来说理想的是,当我创建 G.add_edge("B","C") 时,会创建一个新节点“C”,而不是重用连接到 H 的 on。
    • 那么你需要给新节点起个别的名字。可能是 C1 和 C2。据我所知,NetworkX 不允许多个节点具有相同的标签。
    • 但我需要节点具有相同的。就像我在主线程中所说的那样。我的节点是服务器名称,我无法更改名称,否则我不知道哪个是哪个...但实际上 Thorsten Kranz 不是“错误”的图表是正确的,B 取决于“C 和 D”。只是算法“dfs_successors()”输出 B 只依赖于 D 并且这是错误的谢谢
    • 添加了第二个示例,希望这符合您的需求。
    • 边缘也可以标注吗?
    【解决方案2】:

    我认为您正在寻找的是拓扑排序 http://networkx.github.com/documentation/latest/reference/generated/networkx.algorithms.dag.topological_sort.html

    这仅在您有 DAG(有向无环图)时才有效。 如果是这样,你也可以画出你想要的树 - 像这样:

    import uuid
    import networkx as nx
    import matplotlib.pyplot as plt
    G = nx.DiGraph()
    G.add_edge("A","B")
    G.add_edge("A","H")
    G.add_edge("H","C")
    G.add_edge("B","C")
    G.add_edge("B","D")
    
    order =  nx.topological_sort(G)
    print "topological sort"
    print order
    
    # build tree
    start = order[0]
    nodes = [order[0]] # start with first node in topological order
    labels = {}
    print "edges"
    tree = nx.Graph()
    while nodes:
        source = nodes.pop()
        labels[source] = source
        for target in G.neighbors(source):
            if target in tree:
                t = uuid.uuid1() # new unique id
            else:
                t = target
            labels[t] = target
            tree.add_edge(source,t)
            print source,target,source,t
            nodes.append(target)
    
    nx.draw(tree,labels=labels)
    plt.show()
    

    绘图使用标签映射将节点的id映射到原始标签。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多