我有一组节点和一个名为
当给出一组节点时,我可以通过将所有可能的节点组合传递给
这种方法的问题在于我会得到许多冗余的检查,我希望能够避免这种情况。
foo(u,v)
的函数,可以确定两个节点是否相等。这里的“相等”是指传递性等价:如果1==2
且2==3
,则1==3
;同时,如果1==2
且1!=4
,则2!=4
。当给出一组节点时,我可以通过将所有可能的节点组合传递给
foo(u,v)
函数(该函数仅用于演示目的返回预定结果-它不是真正的功能!)并构建所需的边来查找图中的所有连通分量。像这样:import networkx as nx
import itertools
from matplotlib import pyplot as plt
def foo(u, v):
# this function is simplified, in reality it will do a complex
# calculation to determine whether nodes are equal.
EQUAL_EDGES = {(1, 2), (2, 3), (1, 3), (4, 5)}
return (u, v) in EQUAL_EDGES
def main():
g = nx.Graph()
g.add_nodes_from(range(1, 5 + 1))
for u, v in itertools.combinations(g.nodes, 2):
are_equal = foo(u, v)
print '{u}{sign}{v}'.format(u=u, v=v, sign='==' if are_equal else '!=')
if are_equal:
g.add_edge(u, v)
conn_comps = nx.connected_components(g)
nx.draw(g, with_labels=True)
plt.show()
return conn_comps
if __name__ == '__main__':
main()
这种方法的问题在于我会得到许多冗余的检查,我希望能够避免这种情况。
1==2 # ok
1==3 # ok
1!=4 # ok
1!=5 # ok
2==3 # redundant check, if 1==2 and 1==3 then 2==3
2!=4 # redundant check, if 1!=4 and 1==2 then 2!=4
2!=5 # redundant check, if 1!=5 and 1==2 then 2!=5
3!=4 # redundant check, if 1!=4 and 1==3 then 3!=4
3!=5 # redundant check, if 1!=5 and 1==3 then 3!=5
4==5 # ok
我希望避免在O(n^2)时间复杂度下运行。
有没有正确的方法(或任何Python库中现有的函数)可以通过自定义的foo(u,v)
函数高效地查找所有连接组件?
O(n^2)
的复杂度。你所能做的就是避免冗余比较。 - BlackBearfoo
通过尊重所有节点之间的瞬态相等性来计算两个节点的相等性,那么为什么不让该函数一开始就处理冗余呢?或者反过来,该函数如何确保尊重所有节点之间的瞬态相等性? - a_guestfoo
,那么您的问题就是查找连通组件,我认为您最好的选择是 O(c n),其中 n 是顶点数,c 是连通组件数。可以使用 并查集数据结构 来实现这种复杂度。这在组件数量较少的情况下很好,但在最坏情况下它与 O(n²) 相同。 - Stefbar(u)
来替换测试相等性的函数foo(u, v)
,那么当且仅当foo(u, v) == True
时,bar(u) == bar(v)
,您可以通过将顶点存储到列表字典中,在线性时间内找到连接组件:d = defaultdict(list); for u in g.nodes: d[bar(u)].append(u)
。 - Steffoo
的情况下,我提到了并查集数据结构,但在你的情况下,甚至不需要它来实现 O(c n) 复杂度,因为foo
定义了等价类(这意味着每个连通分量都是完全连接的)。只需保留迄今为止找到的连通分量列表,并将每个新顶点u
与每个连通分量的第一个顶点进行比较;如果存在,则将其添加到它所属的第一个连通分量中,否则将其作为新的连通分量添加。 - Stef