我正在考虑使用networkx创建和维护Directed Acyclic Graph(DAG)。
检查添加边缘是否会导致DiGraph不再是DAG的首选方法是什么?
示例图:
import networkx as nx
G = nx.DiGraph()
G.add_edges_from([(1,2), (1,3), (2,4)]) # no cycles so far
我们得到:
>>> G
1 2 3
2 4
3
4
>>> nx.is_directed_acyclic_graph(G)
True
当我们向图中添加一个循环时:
G.add_edge(4,1) # now we have a cycle
我们得到:
>>> G
1 2 3
2 4
3
4 1
>>> nx.is_directed_acyclic_graph(G)
False
如何检查新边是否会引起循环?到目前为止,我想出的最好的方法是:
def add_dependency(G, n1, n2):
if n2 in nx.ancestors(G, n1):
print('this will create a cycle')
else:
print(f"add {n2} as edge of {n1}")
G.add_edge(n1, n2)
有更好的方法吗?
答案 0 :(得分:1)
在可读性和内存消耗的情况下,您的代码最适合networkx
。请注意,许多问题(尤其是图论)在时间和内存消耗之间权衡。
在您的情况下,您不知道新边是否会创建一个循环,因此您必须重新计算节点内祖先并检查它们(因此,我建议您使用代码)。但是,如果您有密集的图并且大多数新边都不正确,则必须重复重新计算祖先。但是您可以预先计算每个节点的祖先并将它们存储在集合的字典中:d = {n: nx.ancestors(DAG, n) for n in DAG}
搜索复杂度为O(1)
,但是每个边的加法会导致许多节点祖先的重新计算。