我正在使用Python和NetworkX进行图形模型项目的开发。 NetworkX使用字典提供简单且良好的功能:
import networkx as nx
G = nx.DiGraph() # a directed graph
G.add_edge('a', 'b')
print G['a'] # prints {'b': {}}
print G['b'] # prints {}
我想使用有向图,因为我正在编写具有方向性的依赖项(在上面的示例中,我有“b”有条件的闭式形式在“a”的基础上,而不是相反)。 对于给定的节点,我想找到该节点的前驱节点。对于上面的示例,par('b')应返回['a']。NetworkX确实具有后继函数,它可以找到任何节点的子节点。显然,通过遍历所有节点并找到具有'b'作为子节点的节点将起作用,但是这将在节点数(对于我的应用程序来说太昂贵)的数量(将是Ω(n))中进行。我无法想象这么简单的事情会被遗漏在这个制作精良的包中,但是找不到任何东西。一个有效的选项是存储图的有向和无向版本;所有无向边都实际上通过添加两个有向边来实现,因此可以在相邻节点和子节点(它将是前身)之间进行集合差异。问题是我不确定最pythonic的方法如何包装现有的networkx DiGraph和Graph类以实现此目的。实际上,我只想最终得到一个类PGraph,它的行为完全像networkx DiGraph类一样,但除了successors(node)函数外,还有一个predecessors(node)函数。PGraph应该从DiGraph继承并封装Graph(用于predecessors函数)吗?然后,我应该如何强制所有节点和边缘都添加到它包含的有向和无向图中?我应该重新实现添加和删除节点和边缘的函数,以便将它们添加和删除到有向和无向版本中吗?我担心如果我错过了一些模糊的东西,那么以后可能会遇到头疼的问题,这可能不意味着良好的设计。或者(请让这是真的)在networkx.DiGraph中是否有一种简单的方法来获取节点的前身,而我完全错过了它?谢谢你的帮助。编辑:我认为这样做了工作。PGraph从DiGraph继承并封装另一个DiGraph(反向)。我已经覆盖了添加和删除节点和边缘的方法。import networkx as nx
class PGraph(nx.DiGraph):
def __init__(self):
nx.DiGraph.__init__(self)
self.reversed_graph = nx.DiGraph()
def add_node(self, n, attr_dict=None, **attr):
nx.DiGraph.add_node(self, n, attr_dict, **attr)
self.reversed_graph.add_node(n, attr_dict, **attr)
def add_nodes_from(self, ns, attr_dict=None, **attr):
nx.DiGraph.add_nodes_from(self, ns, attr_dict, **attr)
self.reversed_graph.add_nodes_from(ns, attr_dict, **attr)
def add_edge(self, a, b, attr_dict=None, **attr):
nx.DiGraph.add_edge(self, a, b, attr_dict, **attr)
self.reversed_graph.add_edge(b, a, attr_dict, **attr)
def add_edges_from(self, es, attr_dict=None, **attr):
nx.DiGraph.add_edges_from(self, es, attr_dict, **attr)
self.reversed_graph.add_edges_from(es, attr_dict, **attr)
def remove_node(self, n):
nx.DiGraph.remove_node(self, n)
self.reversed_graph.remove_node(n)
def remove_nodes_from(self, ns):
nx.DiGraph.remove_nodes_from(self, ns)
self.reversed_graph.remove_nodes_from(ns)
def remove_edge(self, a, b):
nx.DiGraph.remove_edge(self, b, a)
self.reversed_graph.remove_edge(a, b)
def remove_edges_from(self, es):
nx.DiGraph.remove_edges_from(self, es)
self.reversed_graph.remove_edges_from([ (b,a) for a,b in es])
# the predecessors function I wanted
def predecessors(self, n):
return self.reversed_graph.successors(n)
你对这个解决方案有什么看法?它可能会使内存使用量增加一倍,但我认为这是可以接受的。它是否过于复杂?这是一个好的设计吗?