如何解决Python:在显示为边列表的图中查找连接组件
start | end
a c
b d
e b
我有数千万条边(大约 3000 万条),我无法将整个图形读入内存 - 至少没有使用像 networkx 这样的库,它有点占用内存。
我的目标是在由该列表表示的图中找到包含少于 x
个节点的所有连通组件。
例如,我想获得少于 x=30
节点的所有连接组件。但我不想通过构建整个图然后搜索连接的组件来做到这一点(例如,调用这个 networkx 命令:nx.connected_component_subgraphs(nxg)
)。
有没有一种方法可以只使用边列表文件搜索连接的组件,而无需构建整个图?
附加信息:节点名称是长度为 10-20 个 asci 值的字符串。
解决方法
您首先需要通过为节点分配较短的标识符来减少数据占用空间。您可以将这些较短标识符和原始名称之间的映射写入另一个文件,以便在运行算法后将任何解决方案转换为这些名称。
假设您的节点标识符足够短,您可以将所有内容加载到内存中,以节点标识符为键的字典中。
然后使用 Union-Find 结构和算法来识别连通分量。
最后根据允许的最大大小过滤它们。
有一些库提供了 Union-Find 实现,可以提供更好的性能。下面是 Union-Find 的一个简单实现:
class Node:
def __init__(self,key):
self.key = key
self.parent = self
self.size = 1
class UnionFind(dict):
def find(self,key):
node = self.get(key,None)
if node is None:
node = self[key] = Node(key)
else:
while node.parent != node:
# walk up & perform path compression
node.parent,node = node.parent.parent,node.parent
return node
def union(self,key_a,key_b):
node_a = self.find(key_a)
node_b = self.find(key_b)
if node_a != node_b: # disjoint? -> join!
if node_a.size < node_b.size:
node_a.parent = node_b
node_b.size += node_a.size
else:
node_b.parent = node_a
node_a.size += node_b.size
然后,以下函数将从迭代器加载该结构,并返回大小符合要求的组件:
from collections import defaultdict
def find_components(line_iterator,max_size):
forest = UnionFind()
for line in line_iterator:
forest.union(*line.split())
result = defaultdict(list)
for key in forest.keys():
root = forest.find(key)
if root.size <= max_size:
result[root.key].append(key)
return list(result.values())
这是下图的演示:
data = """x d
c j
i e
f x
n z
a u
g r
w x
p l
u o
m g
k s
t q
y l
h m
n b
k v
e u
i o
r m
n c
x q
f q
j l
s v"""
results = find_components(data.splitlines(),5)
print(results)
这个演示的输出是:
[['i','e','a','u','o'],['g','r','m','h'],['k','s','v']]
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。