【问题标题】:How to delete all related nodes in a directed graph using networkx?如何使用networkx删除有向图中的所有相关节点?
【发布时间】:2025-12-06 23:50:01
【问题描述】:

我不确定我的问题的正确术语是什么,所以我将解释我想要做什么。我有一个有向图,删除一个节点后,我希望也删除所有独立相关的节点。

这是一个例子:

说,我删除节点 '11',我希望节点 '2' 也被删除(在我自己的示例中,它们将是 2 以下的节点,现在也必须删除),因为它不是不再连接到主图。请注意,不应删除节点“9”或“10”,因为节点“8”和“3”仍连接到它们。

我正在使用 python 库 networkx。我搜索了文档,但我不确定术语,所以我不确定这叫什么。如果可能的话,我想使用库提供的函数而不是通过图创建自己的递归(因为我的图很大)。

任何关于如何做到这一点的帮助或建议都会很棒。

谢谢!

【问题讨论】:

  • 你的图总是非循环的,还是可以包含循环?
  • 它不包含任何循环。每个节点基本上是一个每日观察的列表,这些观察与接下来的几天观察相关联。有时,我发现有错误的观察,所以当我删除它时,我希望从该已删除节点派生的其他节点也被删除。

标签: algorithm graph-theory cascading-deletes networkx


【解决方案1】:

我假设以下是正确的:

  • 图表是非循环的。您在评论中提到了这一点,但我想明确指出这是一个初步假设。
  • 有一组已知的根节点。我们需要通过某种方式了解哪些节点始终被认为是可访问的,并且我假设(不知何故)这些信息是已知的。
  • 初始图不包含任何多余的节点。也就是说,如果初始图包含任何应该删除的节点,那么它们已经被删除了。这允许算法通过保持每个节点都应该存在的不变量来工作。

如果是这种情况,那么给定一个初始设置,节点在图中的唯一原因是

  1. 该节点在根可达节点集中,或者
  2. 节点的父节点位于可到达的根节点集中。

因此,每当您从图中删除一个节点时,可能需要删除的唯一节点就是该节点的后代。如果您删除的节点在根集中,您可能需要修剪很多图,如果您删除的节点是一个其自己的后代很少的后代节点,那么您可能需要做的很少。

鉴于此设置,删除节点后,您需要扫描该节点的所有子节点,以查看其中是否有任何其他父节点可以将它们保留在图表中。由于我们假设图中唯一的节点是需要存在的节点,如果已删除节点的子节点至少有一个其他父节点,那么它应该仍然在图中。否则,需要删除该节点。因此,执行删除步骤的一种方法是使用以下递归算法:

  • 对于要删除的节点的每个子节点:
    • 如果该节点只有一个父节点:(它必须是我们要删除的节点)
      • 递归地从图中删除该节点。
  • 从图中删除指定节点。

但是,这可能不是一个直接实现的好算法,因为如果您有一个大图,所涉及的递归可能会变得非常深。因此,您可能希望使用像这样的工作列表算法来实现它:

  • 创建工作清单 W.
  • 将要删除的节点 v 添加到 W。
  • 当 W 不为空时:
    • 从 W 中删除第一个条目;叫它。
    • 对于 w 的每个孩子:
      • 如果该孩子只有一个父母,请将其添加到 W。
    • 从图中删除 w。

这最终是最坏情况的 O(m) 时间,其中 m 是图中的边数,因为理论上每条边都必须被扫描。但是,假设您的图表中有一些冗余,它可能会快得多。

希望这会有所帮助!

【讨论】:

  • 惊人的答案,谢谢它帮助我了解了很多正在发生的事情。给你的问题:如果我不知道初始图是否有多余的节点,这会有很大的不同吗?当我对一个已经持续多年的过程进行观察时,我开始捕捉观察结果并希望在发现错误时对其进行清理。
  • @Lostsoul- 如果您不确定初始图是否有多余的节点,您可以随时运行图搜索以确定哪些节点是不必要的。例如,您可以从您知道有效的每个节点(“根集”)运行深度优先搜索,标记您遇到的每个节点。然后,您可以从图中删除所有未标记的节点。这实际上非常有效(如果您使用深度优先搜索,它所花费的时间与图中节点和边的数量成正比),并且将为您准备好后面的算法。
  • @Lostsoul- 如果您以后对图或图算法有任何疑问,请随时提问!
  • @templateypedef 非常感谢!我想我理解你的意思,但我会尝试代码,所以希望我能看到它的实际效果。谢谢你的帮助!在旁注中,当我第一次开始接触算法时,我问了一个问题,如果蛮力算法可以扩展,你为我回答了这个问题。你不仅教会了我动态编程背后的想法,而且让我对算法非常感兴趣(事实上,我已经打印了你的答案并经常参考它)。您最近还帮助我绘制图表,所以我非常感谢您帮助我奠定了良好的基础!非常感谢,你摇滚!
【解决方案2】:

让我为您提供解决您任务的python networkX 代码:

import networkx as nx
import matplotlib.pyplot as plt#for the purpose of drawing the graphs
DG=nx.DiGraph()
DG.add_edges_from([(3,8),(3,10),(5,11),(7,11),(7,8),(11,2),(11,9),(11,10),(8,9)])
DG.remove_node(11)

connected_components 方法出人意料地不适用于有向图,因此我们将图转为无向图,找出未连接的节点,然后将它们从有向图中删除

UG=DG.to_undirected()
not_connected_nodes=[]
for component in nx.connected_components(UG):
    if len(component)==1:#if it's not connected, there's only one node inside
        not_connected_nodes.append(component[0])
for node in not_connected_nodes:
    DG.remove_node(node)#delete non-connected nodes

如果您想查看结果,请在脚本中添加以下两行:

nx.draw(DG)
plt.show() 

【讨论】: