在python中,列表通过递归生存的问题;在图上查找所有可能的路由

在python中,列表通过递归生存的问题;在图上查找所有可能的路由,python,list,recursion,graph,Python,List,Recursion,Graph,我正在编写一个python程序,它获取一个完全连接的图(您可以从任何其他节点转到图上的任何节点),并在该图上查找所有可能的路由,这些路由短于给定的最大距离 这是我到目前为止编写的代码: def find_all_routes (cur_node, graph, willing_to_travel, visited, routesdict): """ Finds all routes possible within a certain distance. inputs

我正在编写一个python程序,它获取一个完全连接的图(您可以从任何其他节点转到图上的任何节点),并在该图上查找所有可能的路由,这些路由短于给定的最大距离

这是我到目前为止编写的代码:

def find_all_routes (cur_node, graph, willing_to_travel, visited, routesdict):
    """ Finds all routes possible within a certain distance.
    inputs
        cur_node: a dictionary with n entries, each of which is the distance to the nth
            dictionary in graph.
        graph: a list of n dictionaries, each of which contains n entries, each of which
            is the distance to the nth item in the list.
        willing_to_travel: the maximum distance we are willing to travel.
        visited: initialized as an empty list, will be populated nodes we've been to.
        all_routes: initialized as an empty list.
    Affects:
        all_routes is populated with every route permutation that can be traveled in under willing_to_travel distance.
    """
    #Add our current location to the visited list.
    for i in cur_node:
        if cur_node[i] == 0:
            visited.append(graph[i])

    # Add the current route to the dictionary.
    entry_no = len(routesdict)
    routesdict[entry_no] = visited
    print ("routesdict", routesdict)            # Just for diagnostic purposes.

    # Recursion with other nodes we can reach as the new start node.
    for i in cur_node:                               # For every place in the dictionary
        if graph[i] not in visited:                  # if we have not been there
            if cur_node[i] <= willing_to_travel:     # And if we can afford to go there
                find_all_routes(graph[i], graph, willing_to_travel - cur_node[i], visited, routesdict)

    return routesdict

def main():

    graph = [
        {0: 0.00, 1: 0.12, 2: 0.10},
        {0: 0.12, 1: 0.00, 2: 0.22},
        {0: 0.10, 1: 0.22, 2: 0.00}]

    max_distance = 10.0
    been_to = []
    routesdict = dict()

    routes = find_all_routes (graph[0], graph, max_distance, been_to, routesdict)

print ("Final output: ", routes)

if __name__ == "__main__":
    main()
这很难看,但根据我们访问的节点来改写它,它是这样的:

routesdict [0]
routesdict [0, 1] [0, 1]
routesdict [0, 1, 2]  [0, 1, 2] [0, 1, 2]
Final out: [0, 1, 2]  [0, 1, 2] [0, 1, 2]
All possible routes*: [0], [0,1], [0,1,2], [0,2], [0,2,1]
*If we must start at node 0.
对于三节点图,如果最大距离足够高,可以完成所有可能的路线,我希望输出看起来更像这样:

routesdict [0]
routesdict [0, 1] [0, 1]
routesdict [0, 1, 2]  [0, 1, 2] [0, 1, 2]
Final out: [0, 1, 2]  [0, 1, 2] [0, 1, 2]
All possible routes*: [0], [0,1], [0,1,2], [0,2], [0,2,1]
*If we must start at node 0.
===============

现在,我想我看到了这个问题,但我不能很好地思考解决它。问题是,我保留了“已访问”列表的标识,而不是删除“已访问”的当前值,然后继续

因此,第一次通过递归,routesdict[0]被定义为“已访问”,并且它正确地将节点[0]作为第一条路由。但是当访问被更改时,routesdict[0]被更新,现在它显示为[0,1]

这与阻止函数执行我希望它执行的递归是一样的,这就是为什么它给了我三条可能的路径,而不是我期望的五条

那么,有没有一种好方法可以在深入递归的同时保留我的“已访问”列表,而不将该列表追溯到世界其他地方

谢谢你的阅读

编辑:

我已经解决了将线路改为routesdict的问题

routesdict[entry_no] = visited[:]

但是我更不知道访问列表是否会破坏我的递归

两个问题都是由同一件事引起的:Python通过引用而不是通过值来传递列表

首先,简而言之,这意味着什么:

当用
a
作为int调用
foo(a)
时,在
foo()
内部,只得到
a
的值,而不是它在内存中的实际位置。你的论文上写了
a
,你展示了
foo()
,“这是
a
,把它写下来。”

但是,当您使用
b
作为列表或对象调用
bar(b)
时,您不会得到
b
的值,而是得到
b
本身,即内存位置。你的论文上仍然有
b
,但是你对
bar()
,“嘿,
b
非常复杂,可能不值得复制到一张新的纸上。你可以分享我的论文。”这对于防止你的程序变得非常慢很好,但是——正如你所经历的那样——这意味着任何更改
bar()
make to
b
change
b
无处不在

要解决问题,应该传递不希望更改的对象的副本。在将
访问的
添加到
路由dict
时,您已经了解到了这一点,但实际上您应该这样做

find_all_routes(graph[i], graph, willing_to_travel - cur_node[i], visited[:], routesdict)

这意味着对
find_all_routes()
的每次调用都会得到它自己的、已访问的
的个人副本

这两个问题都是由同一件事引起的:Python通过引用而不是通过值传递列表

首先,简而言之,这意味着什么:

当用
a
作为int调用
foo(a)
时,在
foo()
内部,只得到
a
的值,而不是它在内存中的实际位置。你的论文上写了
a
,你展示了
foo()
,“这是
a
,把它写下来。”

但是,当您使用
b
作为列表或对象调用
bar(b)
时,您不会得到
b
的值,而是得到
b
本身,即内存位置。你的论文上仍然有
b
,但是你对
bar()
,“嘿,
b
非常复杂,可能不值得复制到一张新的纸上。你可以分享我的论文。”这对于防止你的程序变得非常慢很好,但是——正如你所经历的那样——这意味着任何更改
bar()
make to
b
change
b
无处不在

要解决问题,应该传递不希望更改的对象的副本。在将
访问的
添加到
路由dict
时,您已经了解到了这一点,但实际上您应该这样做

find_all_routes(graph[i], graph, willing_to_travel - cur_node[i], visited[:], routesdict)

这意味着每次调用
find_all_routes()
都会得到自己的
已访问的
个人副本

非常感谢!非常清楚的回答。我只是无法完全理解它。当我只需要按三下键的时候,我花了好几个小时试图让它工作,这有点令人沮丧,但嘿,这就是生活!完全地这就是为什么对于任何打算从事编程职业的人来说,在某个时候使用低级语言都是一个好主意。你开始看到很多以前没有看到的东西。非常感谢!非常清楚的回答。我只是无法完全理解它。当我只需要按三下键的时候,我花了好几个小时试图让它工作,这有点令人沮丧,但嘿,这就是生活!完全地这就是为什么对于任何打算从事编程职业的人来说,在某个时候使用低级语言都是一个好主意。你开始看到很多以前没有看到的东西。