获取一个起始节点的所有周期的一种方法是:
def cycles(graph, start):
results = []
paths = [(start,)]
while paths:
path = paths.pop()
childs = set(graph.get(path[-1], []))
if start in childs:
results.append(path)
paths.extend(
(path + (child,))
for child in childs.difference(path)
)
return results
使用您的图表和起始节点E,您将获得(print(cycles(g, 'E')) 和g 您的字典):
[('E', 'F', 'G', 'H', 'I', 'D'),
('E', 'F', 'G', 'H', 'I', 'J', 'D'),
('E', 'F', 'C')]
如果您想要一个图表中的所有循环,您将不得不做更多的工作:一个单一的起始节点通常不会导致一个图表的所有循环。实现这一目标的一种方法是遍历所有节点,应用cycles,然后收集所有结果:
result = [cycle for node in g for cycle in cycles(g, node)]
[('E', 'F', 'G', 'H', 'I', 'J', 'D'),
('E', 'F', 'G', 'H', 'I', 'D'),
('E', 'F', 'C'),
('F', 'G', 'H', 'I', 'J', 'D', 'E'),
('F', 'G', 'H', 'I', 'D', 'E'),
('F', 'C', 'E'),
('C', 'E', 'F'),
('G', 'H', 'I', 'J', 'D', 'E', 'F'),
('G', 'H', 'I', 'D', 'E', 'F'),
('H', 'I', 'J', 'D', 'E', 'F', 'G'),
('H', 'I', 'D', 'E', 'F', 'G'),
('I', 'J', 'D', 'E', 'F', 'G', 'H'),
('I', 'D', 'E', 'F', 'G', 'H'),
('J', 'D', 'E', 'F', 'G', 'H', 'I'),
('D', 'E', 'F', 'G', 'H', 'I'),
('D', 'E', 'F', 'G', 'H', 'I', 'J')]
但这种方式会导致一些冗余:('E', 'F', 'C')、('C', 'E', 'F') 和 ( 'F', 'C', 'E') 本质上是相同的(等等)。如果你想摆脱它,你可以这样做:
results = []
d = {node: set(g.get(node, [])) for node in g}
nodes = list(d)
while nodes:
node = nodes.pop()
results.extend(cycles(d, node))
del d[node]
for other_node in d:
d[other_node].discard(node)
print(results):
[('D', 'E', 'F', 'G', 'H', 'I'),
('D', 'E', 'F', 'G', 'H', 'I', 'J'),
('C', 'E', 'F')]