我正在尝试一些广义AI问题的搜索算法,其中之一就是深度优先搜索。我已经将广度优先搜索,贪婪和A *搜索从它们的自然递归形式转换为迭代形式,但是使用深度优先搜索({1}}进行深度优先搜索会遇到更多麻烦(尽管它不会超出我的能力,我不确定最狡猾的方式,所以问题)。
即使是一些中型问题,我也遇到了CPython的1000递归调用限制。后继状态是懒惰生成的(cleanly
是生成器,而不是列表),并且需要从初始状态开始的路径。
从使用调用堆栈转移到显式堆栈的最pythonic方法是什么?应该在堆栈中存储多少信息?回溯时(当没有状态返回非空列表时),从堆栈前面弹出死信息的最佳方法是什么?
_generate_states
答案 0 :(得分:4)
这是一个解决方案,可以保持发电机周围保持所需的懒惰属性:
def dfs(initial, goal, capacity):
# These three variables form the "stack".
closed_set = {initial}
stack = [initial]
gens = [_generate_states(initial, capacity)]
while stack:
cur = stack[-1]
gen = gens[-1]
try:
state = next(gen)
except StopIteration:
# This node is done
closed_set.discard(cur)
gens.pop()
stack.pop()
continue
if state == goal:
return stack
if state not in closed_set:
closed_set.add(state)
stack.append(state)
gens.append(_generate_states(state, capacity))
return None
请注意,当找到目标时,路径是堆栈,因为堆栈是访问到达当前节点的节点的记录。
答案 1 :(得分:3)
我假设您知道如何使用堆栈迭代地实现DFS(它与BFS基本相同,只是LIFO而不是FIFO),因此我将发布一些通用的tipp。
collections.deque
作为堆栈,该堆栈针对快速追加和弹出元素进行了优化。closed_set
的集合而不是列表。 (如果你想找到最短的路径,可以使用地图{state:depth}。)在这种情况下,不确定如何使用生成器,因此您的堆栈将保持深度x分支因子元素...或者您可以将生成器放在堆栈,而不是实际的元素?只是一个想法...
答案 2 :(得分:1)
以下是我将如何创建迭代深度优先搜索。它使用candidate_states
作为下一个应该探索的状态堆栈。您可以使用parents
字典重构从任何访问节点到初始节点的路径。
def reconstruct_path(state, parents):
path = []
while state != None:
path.append(state)
state = parents[state]
path.reverse()
return path
def dfs(initial, goal):
visited_states = set()
candidate_states = [initial]
parents = {initial: None}
while len(candidate_states) > 0:
cur_state = candidate_states.pop()
if cur_state in visited_states: continue
if cur_state == goal:
return reconstruct_path(cur_state, parents)
for state in _generate_states(cur_state):
parents[state] = cur_state
candidate_states.append(state)
return None