避免Python的堆栈

时间:2012-10-02 15:21:40

标签: python recursion artificial-intelligence iteration depth-first-search

我正在尝试一些广义AI问题的搜索算法,其中之一就是深度优先搜索。我已经将广度优先搜索,贪婪和A *搜索从它们的自然递归形式转换为迭代形式,但是使用深度优先搜索({1}}进行深度优先搜索会遇到更多麻烦(尽管它不会超出我的能力,我不确定最狡猾的方式,所以问题)。

即使是一些中型问题,我也遇到了CPython的1000递归调用限制。后继状态是懒惰生成的(cleanly是生成器,而不是列表),并且需要从初始状态开始的路径。

从使用调用堆栈转移到显式堆栈的最pythonic方法是什么?应该在堆栈中存储多少信息?回溯时(当没有状态返回非空列表时),从堆栈前面弹出死信息的最佳方法是什么?

_generate_states

3 个答案:

答案 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。

  • 当迭代地实现DFS时,您应该使用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