我正在为课程get_connected_components
编写一个函数Graph
:
def get_connected_components(self):
path=[]
for i in self.graph.keys():
q=self.graph[i]
while q:
print(q)
v=q.pop(0)
if not v in path:
path=path+[v]
return path
我的图表是:
{0: [(0, 1), (0, 2), (0, 3)], 1: [], 2: [(2, 1)], 3: [(3, 4), (3, 5)], \
4: [(4, 3), (4, 5)], 5: [(5, 3), (5, 4), (5, 7)], 6: [(6, 8)], 7: [], \
8: [(8, 9)], 9: []}
其中键是节点,值是边缘。我的功能给了我这个连接的组件:
[(0, 1), (0, 2), (0, 3), (2, 1), (3, 4), (3, 5), (4, 3), (4, 5), (5, 3), \
(5, 4), (5, 7), (6, 8), (8, 9)]
但我会有两个不同的连接组件,例如:
[[(0, 1), (0, 2), (0, 3), (2, 1), (3, 4), (3, 5), (4, 3), (4, 5), \
(5, 3), (5, 4), (5, 7)],[(6, 8), (8, 9)]]
我不明白我犯了哪个错误。 任何人都可以帮助我吗?
答案 0 :(得分:15)
我喜欢这个算法:
def connected_components(neighbors):
seen = set()
def component(node):
nodes = set([node])
while nodes:
node = nodes.pop()
seen.add(node)
nodes |= neighbors[node] - seen
yield node
for node in neighbors:
if node not in seen:
yield component(node)
它不仅短而优雅,而且速度快。像这样使用它(Python 2.7):
old_graph = {
0: [(0, 1), (0, 2), (0, 3)],
1: [],
2: [(2, 1)],
3: [(3, 4), (3, 5)],
4: [(4, 3), (4, 5)],
5: [(5, 3), (5, 4), (5, 7)],
6: [(6, 8)],
7: [],
8: [(8, 9)],
9: []}
new_graph = {node: set(each for edge in edges for each in edge)
for node, edges in old_graph.items()}
components = []
for component in connected_components(new_graph):
c = set(component)
components.append([edge for edges in old_graph.values()
for edge in edges
if c.intersection(edge)])
print components
结果是:
[[(0, 1), (0, 2), (0, 3), (2, 1), (3, 4), (3, 5), (4, 3), (4, 5), (5, 3), (5, 4), (5, 7)],
[(6, 8), (8, 9)]]
答案 1 :(得分:2)
让我们简化图表表示:
myGraph = {0: [1,2,3], 1: [], 2: [1], 3: [4,5],4: [3,5], 5: [3,4,7], 6: [8], 7: [],8: [9], 9: []}
这里我们有函数返回一个字典,其键是根,其值是连接的组件:
def getRoots(aNeigh):
def findRoot(aNode,aRoot):
while aNode != aRoot[aNode][0]:
aNode = aRoot[aNode][0]
return (aNode,aRoot[aNode][1])
myRoot = {}
for myNode in aNeigh.keys():
myRoot[myNode] = (myNode,0)
for myI in aNeigh:
for myJ in aNeigh[myI]:
(myRoot_myI,myDepthMyI) = findRoot(myI,myRoot)
(myRoot_myJ,myDepthMyJ) = findRoot(myJ,myRoot)
if myRoot_myI != myRoot_myJ:
myMin = myRoot_myI
myMax = myRoot_myJ
if myDepthMyI > myDepthMyJ:
myMin = myRoot_myJ
myMax = myRoot_myI
myRoot[myMax] = (myMax,max(myRoot[myMin][1]+1,myRoot[myMax][1]))
myRoot[myMin] = (myRoot[myMax][0],-1)
myToRet = {}
for myI in aNeigh:
if myRoot[myI][0] == myI:
myToRet[myI] = []
for myI in aNeigh:
myToRet[findRoot(myI,myRoot)[0]].append(myI)
return myToRet
我们试一试:
print getRoots(myGraph)
{8:[6,8,9],1:[0,1,2,3,4,5,7]}
答案 2 :(得分:2)
之前的答案很棒。无论如何,我花了一点时间来了解发生了什么。所以,我以这种方式重构代码,这对我来说更容易阅读。我留下代码,以防有人发现它更容易(它在python 3.6中运行)
def get_all_connected_groups(graph):
already_seen = set()
result = []
for node in graph:
if node not in already_seen:
connected_group, already_seen = get_connected_group(node, already_seen)
result.append(connected_group)
return result
def get_connected_group(node, already_seen):
result = []
nodes = set([node])
while nodes:
node = nodes.pop()
already_seen.add(node)
nodes = nodes or graph[node] - already_seen
result.append(node)
return result, already_seen
graph = {
0: {0, 1, 2, 3},
1: set(),
2: {1, 2},
3: {3, 4, 5},
4: {3, 4, 5},
5: {3, 4, 5, 7},
6: {6, 8},
7: set(),
8: {8, 9},
9: set()}
components = get_all_connected_groups(graph)
print(components)
结果:
Out[0]: [[0, 1, 2, 3, 4, 5, 7], [6, 8, 9]]
另外,我简化了输入和输出。我认为打印组中的所有节点
更清楚一些答案 3 :(得分:0)
如果使用adjacency list表示图形,则可以使用此生成器函数(实现BFS)来获取所有连接的组件:
from collections import deque
def connected_components(graph):
seen = set()
for root in range(len(graph)):
if root not in seen:
seen.add(root)
component = []
queue = deque([root])
while queue:
node = queue.popleft()
component.append(node)
for neighbor in graph[node]:
if neighbor not in seen:
seen.add(neighbor)
queue.append(neighbor)
yield component
演示:
graph = [
[1, 2, 3], # neighbors of node "0"
[0, 2], # neighbors of node "1"
[0, 1], # ...
[0, 4, 5],
[3, 5],
[3, 4, 7],
[8],
[5],
[9, 6],
[8]
]
print(list(connected_components(graph))) # [[0, 1, 2, 3, 4, 5, 7], [6, 8, 9]]