Python:当多个子节点引用回父节点时,如何在递归循环中找到多个路径?

时间:2013-02-26 00:26:03

标签: python recursion

我正在使用递归来查找从某个点A到某个点D的路径。 我正在横穿图表找到路径。

让我们说:

Graph = {'A':['route1','route2'],'B':['route1','route2','route3','route4'],'C':['route3' ,'route4'],'D':['route4']}

可通过以下方式访问:

A - > route1,route2

B - > route2,route 3,route 4

C - > route3,route4

此路径中有两种解决方案,从A - > d:

route1 - > route2 - >路径4

route1 - > route2 - > route3 - >路径4

由于B点和A点都有路径1和路径2.有一个无限循环,所以每当我添加一个检查 我访问节点(0或1值)。

然而,通过检查,我只得到一个解决方案:route1 - > route2 - > route4,而不是其他可能的解决方案。

以下是实际编码:路由将被Reactions取代。

def find_all_paths(graph,start, end, addReaction, passed = {}, reaction = [] ,path=[]):

    passOver =  passed 

    path = path + [start]   
    reaction = reaction + [addReaction]
    if start == end:
        return [reaction] 
    if not graph.has_key(start):
        return []

    paths=[]
    reactions=[]

    for x in range (len(graph[start])):    
        for y in range (len(graph)):
            for z in range (len(graph.values()[y])):
                if (graph[start][x] == graph.values()[y][z]): 
                    if passOver.values()[y][z] < 161 :
                        passOver.values()[y][z] = passOver.values()[y][z] + 1
                            if (graph.keys()[y] not in path):
                                newpaths = find_all_paths(graph, (graph.keys()[y]), end, graph.values()[y][z], passOver , reaction, path)
                            for newpath in newpaths:
                                reactions.append(newpath)
    return reactions

以下是方法调用:dic_passOver是一个字典,用于跟踪节点是否被访问

solution = (find_all_paths( graph, "M_glc_DASH_D_c', 'M_pyr_c', 'begin', dic_passOver ))

我的问题似乎是,一旦访问了路径,就无法再访问,因此其他可能的解决方案是不可能的。我通过在161处添加最大递归量来解释这一点,其中找到了我的特定代码的所有可能路由。

if passOver.values()[y][z] < 161 :
                        passOver.values()[y][z] = passOver.values()[y][z] + 1

但是,这看起来非常低效,而且我的大部分数据都是带有数千个索引的图表。此外,我不知道查找所有路由的允许节点访问量。数字161是手动计算出来的。

1 个答案:

答案 0 :(得分:3)

好吧,我无法理解你对图表的表示。但这是一种通用算法,可用于查找避免无限循环的所有路径。

首先,您需要将图表表示为将节点映射到它们所连接的节点集的字典。例如:

graph = {'A':{'B','C'}, 'B':{'D'}, 'C':{'D'}}

这意味着从A开始,您可以转到BC。从B,您可以转到D,也可以从C转到D。我们假设链接是单向的。如果您希望它们是双向的,只需添加链接以便双向进行。

如果您以这种方式表示图表,则可以使用以下函数查找所有路径:

def find_all_paths(start, end, graph, visited=None):
    if visited is None:
        visited = set()

    visited |= {start}
    for node in graph[start]:
        if node in visited:
            continue
        if node == end:
            yield [start,end]
        else:
            for path in find_all_paths(node, end, graph, visited):
                yield [start] + path

使用示例:

>>> graph = {'A':{'B','C'}, 'B':{'D'}, 'C':{'D'}}
>>> for path in find_all_paths('A','D', graph):
...   print path
... 
['A', 'C', 'D']
['A', 'B', 'D']
>>> 

编辑以考虑澄清图表表示的评论

下面是一个函数,用于转换图形表示(假设我理解正确并且路由是双向的)到上面算法中使用的那个

def change_graph_representation(graph):
    reverse_graph = {}
    for node, links in graph.items():
        for link in links:
            if link not in reverse_graph:
                reverse_graph[link] = set()
            reverse_graph[link].add(node)

    result = {}
    for node,links in graph.items():
        adj = set()
        for link in links:
            adj |= reverse_graph[link]
        adj -= {node}
        result[node] = adj
    return result

如果根据链接找到路径很重要,而不是遍历的节点,则可以保留此信息,如下所示:

def change_graph_representation(graph):
    reverse_graph = {}
    for node, links in graph.items():
        for link in links:
            if link not in reverse_graph:
                reverse_graph[link] = set()
            reverse_graph[link].add(node)

    result = {}
    for node,links in graph.items():
        adj = {}
        for link in links:
            for n in reverse_graph[link]:
                adj[n] = link
        del(adj[node])
        result[node] = adj
    return result

并使用此修改后的搜索:

def find_all_paths(start, end, graph, visited=None):
    if visited is None:
        visited = set()

    visited |= {start}
    for node,link in graph[start].items():
        if node in visited:
            continue
        if node == end:
            yield [link]
        else:
            for path in find_all_paths(node, end, graph, visited):
                yield [link] + path

这将为您提供跟踪链接而不是遍历节点的路径。希望这会有所帮助:)