You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在NetworkX树中计算每个节点子节点的边权重总和

如何在NetworkX有向树中计算每个节点所有子节点相关边的权重总和

需求说明:在NetworkX构建的有向树中,为每个节点计算其所有子节点相关边的权重总和——即该节点到直接子节点的边权重,加上所有子节点各自子树中所有边的权重之和。例如:

  • 非叶子节点的总和 = 自身到子节点的边权重 + 子节点的子树边权重总和
  • 根节点的总和为全图所有边的权重总和
  • 叶子节点(无后续子节点)的总和为0

基础示例代码

import networkx as nx
import matplotlib.pyplot as plt
G = nx.DiGraph()

G.add_node("ROOT")
for i in range(5):
    G.add_node("Child_%i" % i)
    G.add_node("Grandchild_%i" % i)
    G.add_node("Greatgrandchild_%i" % i)

    G.add_edge("ROOT", "Child_%i" % i, weight=(i+1))
    G.add_edge("Child_%i" % i, "Grandchild_%i" % i, weight=(2*i+1))
    G.add_edge("Grandchild_%i" % i, "Greatgrandchild_%i" % i, weight=(3*i+1))

from networkx.drawing.nx_pydot import graphviz_layout
pos = graphviz_layout(G, prog="dot")
nx.draw(G, pos, with_labels=True, arrows=True)
labels = nx.get_edge_attributes(G,'weight')
nx.draw_networkx_edge_labels(G,pos,edge_labels=labels)
plt.show()

期望计算结果示例

  • Grandchild_4 = 13(对应边Grandchild_4→Greatgrandchild_4的权重)
  • Child_4 = 22(边Child_4→Grandchild_4的权重9 + Grandchild_4的总和13)
  • Grandchild_3 = 10(边Grandchild_3→Greatgrandchild_3的权重)
  • Child_3 = 17(边Child_3→Grandchild_3的权重7 + Grandchild_3的总和10)
  • ...
  • ROOT = 全图所有边的权重总和

示例图


测试示例与方案分析

以下是补充的测试代码,包含两种解决方案,其中一种符合需求,另一种不符合:

import networkx as nx
import matplotlib.pyplot as plt
from pprint import pp

G = nx.DiGraph()

G.add_node("ROOT")
s = 0
for i in range(5):
    G.add_node("C_%i" % i)
    G.add_node("GC_%i" % i)
    G.add_node("GGC_%i" % i)
    G.add_node("GGD_%i" % i)

    G.add_edge("ROOT", "C_%i" % i, weight=(i+1))
    s += i+1
    G.add_edge("C_%i" % i, "GC_%i" % i, weight=(2*i+1))
    s += 2*i+1
    G.add_edge("GC_%i" % i, "GGC_%i" % i, weight=(3*i+1))
    s += 3*i+1
    G.add_edge("GC_%i" % i, "GGD_%i" % i, weight=(4 * i + 1))
    s +=4 * i + 1

print("全图边权重总和:", s)

# 方案1:基于叶子节点回溯计算(符合需求)
leaves = {n for n in G.nodes() if G.out_degree(n)==0}
out = {}
for n in leaves:
    # 获取从ROOT到当前叶子的路径边
    path_edges = next(nx.all_simple_edge_paths(G, 'ROOT', n))
    # 反向遍历路径边,累加计算
    for parent, child in reversed(path_edges):
        out[parent] = out.get(parent, 0) + out.get(child, 0) + G[parent][child]['weight']

print("\n方案1计算结果:")
pp(out)

# 方案2:基于BFS边的求和(不符合需求)
data = {
    node: sum(G.edges[edge]["weight"] for edge in nx.bfs_edges(G, node))
    for node in G.nodes
}

print("\n方案2计算结果:")
pp(data)

方案对比

  1. 方案1(可行):
    通过定位所有叶子节点(出度为0的节点),回溯每个叶子到根节点的路径,反向遍历路径中的边,累加当前边权重与子节点已计算的总和,最终得到父节点的子树边权重总和。利用了有向树路径唯一性的特性,结果符合需求。

  2. 方案2(不可行):
    nx.bfs_edges(G, node)仅返回当前节点到所有直接/间接子节点的边,仅统计这些边的权重之和,没有累加子节点自身的子树边总和,因此得到的结果只是当前节点到子节点的直接边权重之和,并非完整的子树边权重总和。


更简洁的通用实现

使用递归后序遍历的方式,先计算所有子节点的子树总和,再加上当前节点到子节点的边权重,代码简洁且通用:

def calculate_subtree_edge_sum(G, node):
    total = 0
    # 遍历当前节点的所有直接后继(子节点)
    for child in G.successors(node):
        edge_weight = G[node][child]['weight']
        # 累加当前边权重 + 子节点的子树总和
        total += edge_weight + calculate_subtree_edge_sum(G, child)
    return total

# 计算所有节点的子树边权重总和
result = {node: calculate_subtree_edge_sum(G, node) for node in G.nodes}

print("\n递归法计算结果:")
pp(result)

该方法适用于任何有向树结构,计算逻辑清晰,结果完全符合需求。

内容的提问来源于stack exchange,提问作者BlueTrin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 11:47:13