我正在尝试创建一个回溯函数,它将返回从根到GOAL
我的path_holder:
path_holder = {
'node1':['node2','node3','node5'],
'node2':['node1','node8','node10'],
'node3':['node4','node6']},
'node4':['node2','node1','node3'],
'node5':['DEADEND'],
'node6':['GOAL']
....
}
在我的path_holder
输入中,它是BFS的输出,因此第一个节点是根,最后一个节点是目标。因为path_holder
输入是BFS的输出,所以当找到GOAL
时它会停止,因此所有搜索GOAL
所需的先前节点的分支的节点都会添加到{ {1}}也是。
目前我陷入了发生无限循环的while循环。我的一般策略是从path_holder
节点开始,并使用此节点的密钥来查找此密钥在另一个密钥(节点)列表中的位置。一旦我找到该节点(其列表包含密钥),我将节点的密钥设置为新目标。 (令人困惑的句子抱歉)
这个图可能包含循环,这可能就是为什么我也会得到无限循环。
我的回溯功能:
GOAL
ex:输出
def backtrace(path_holder, root, goal):
dct = {}
for d in path_holder:
dct.update(d)
rootnode = root.keys()[0]
goal = goal.keys()[0]
#x = len(path_holder)
path = []
path.append(goal)
#for i in reversed(xrange(x):
# path_holder[i].keys()
while goal != rootnode:
# find key that contains goal in list
for i in dct:
#print i
for j in dct[i] :
if j not in path:
if j == goal:
path.append(i)
goal = i
# append key that has goal in the list
# set goal to be the key that was appended
# repeat
return path
答案 0 :(得分:6)
运行代码时出现以下错误:
>>> backtrace(path_holder, 'node1', 'GOAL')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "q20349609.py", line 13, in backtrace
dct.update(d)
ValueError: dictionary update sequence element #0 has length 1; 2 is required
那是因为当你迭代这样的字典时:
for d in path_holder:
你得到的是字典的键。因此d
取值为'node1'
,'node2'
等等,您无法将这些值传递给dict.update
方法。
但是你到底想要做什么呢?如果您尝试将path_holder
复制到dct
,则可以写下:
dct = dict(path_holder)
但为什么还要复制呢?为什么不使用path_holder
?
修复了错误#1,程序运行但陷入无限循环。那是因为这些方面:
if j not in path:
if j == goal:
path.append(i)
这些行意味着只有路径中的节点({1}}尚未在路径中,但等于目标时,才会向路径添加节点。但是等一下,j
已经在这一点上了。因此,两个条件不能同时满足。因此,没有任何东西被添加到路径中!
显然行:
goal
应该是:
if j not in path:
因为if i not in path:
是我们正在考虑添加到路径的节点。
修复了错误#1和#2,程序取得了一些进展,但仍陷入无限循环。如果我们在i
之后添加行print(path)
,那么我们会得到以下输出,直到它被卡住:
path.append(i)
您可以看到搜索出错了:从>>> backtrace(path_holder, 'node1', 'GOAL')
['GOAL', 'node6']
['GOAL', 'node6', 'node3']
['GOAL', 'node6', 'node3', 'node4']
已经转到node3
,但没有从node4
到node4
的路线,除了经历GOAL
的那个。搜索永远不会考虑在路径中添加node3
,因为它已经存在。
当您找到node3
之类的节点的路径时,您无法知道该节点是否位于从node4
到GOAL
的最短路径上。您现在所能知道的是如果 node1
位于从node4
到GOAL
的最短路径上,那么你'我会通过node1
到达那里。这就是你必须记录的一切。
以下是我实现此操作的方法,使用字典node3
为每个节点记录从visited
到该节点的最短路径上的上一个节点,以及collections.deque
来维护我们可能尚未访问过的邻居节点队列。
start
注意:
您的变量from collections import deque
class NotFound(Exception): pass
def search(graph, start, goal):
"""Find the shortest path from start to goal in graph (which must be a
map from a node to an iterable of adjacent nodes), using
breadth-first search.
>>> graph = {
... 1: [2, 4, 5],
... 2: [1],
... 3: [4, 6],
... 4: [2, 1, 3],
... 5: [],
... 6: [7],
... 7: [],
... }
>>> search(graph, 1, 7)
[1, 4, 3, 6, 7]
>>> search(graph, 1, 1)
[1]
>>> search(graph, 5, 1) # doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
...
NotFound: No path from 5 to 1
"""
visited = {start: None}
queue = deque([start])
while queue:
node = queue.popleft()
if node == goal:
path = []
while node is not None:
path.append(node)
node = visited[node]
return path[::-1]
for neighbour in graph[node]:
if neighbour not in visited:
visited[neighbour] = node
queue.append(neighbour)
raise NotFound('No path from {} to {}'.format(start, goal))
包含graph中称为adjacency list representation的数据结构。所以我调用了这个变量path_holder
。
我写了一个docstring来解释函数的作用以及如何调用它。 docstring还包含可以使用doctest
模块运行的嵌入式代码示例。
您的功能会从目标向后搜索到开始。但这与从开始到目标的向前搜索一样,所有边缘都被颠倒了。所以我通过搜索来保持简单。