Python 有人能解释一下深度优先搜索的实现吗?

Python 有人能解释一下深度优先搜索的实现吗?,python,algorithm,depth-first-search,Python,Algorithm,Depth First Search,因此,我现在正在学习搜索算法,如果有人能解释一下深度优先搜索的实现方式,我会非常感激。我确实理解深度优先搜索作为一种算法是如何工作的,但我很难理解它是如何在这里实现的 感谢您的耐心和理解,以下是代码: map = {(0, 0): [(1, 0), (0, 1)], (0, 1): [(1, 1), (0, 2)], (0, 2): [(1, 2), (0, 3)], (0, 3): [(1, 3), (0, 4)], (0, 4): [(1, 4), (0, 5)],

因此,我现在正在学习搜索算法,如果有人能解释一下深度优先搜索的实现方式,我会非常感激。我确实理解深度优先搜索作为一种算法是如何工作的,但我很难理解它是如何在这里实现的

感谢您的耐心和理解,以下是代码:

map = {(0, 0): [(1, 0), (0, 1)],
   (0, 1): [(1, 1), (0, 2)],
   (0, 2): [(1, 2), (0, 3)],
   (0, 3): [(1, 3), (0, 4)],
   (0, 4): [(1, 4), (0, 5)],
   (0, 5): [(1, 5)],
   (1, 0): [(2, 0), (1, 1)],
   (1, 1): [(2, 1), (1, 2)],
   (1, 2): [(2, 2), (1, 3)],
   (1, 3): [(2, 3), (1, 4)],
   (1, 4): [(2, 4), (1, 5)],
   (1, 5): [(2, 5)],
   (2, 0): [(3, 0), (2, 1)],
   (2, 1): [(3, 1), (2, 2)],
   (2, 2): [(3, 2), (2, 3)],
   (2, 3): [(3, 3), (2, 4)],
   (2, 4): [(3, 4), (2, 5)],
   (2, 5): [(3, 5)],
   (3, 0): [(4, 0), (3, 1)],
   (3, 1): [(4, 1), (3, 2)],
   (3, 2): [(4, 2), (3, 3)],
   (3, 3): [(4, 3), (3, 4)],
   (3, 4): [(4, 4), (3, 5)],
   (3, 5): [(4, 5)],
   (4, 0): [(5, 0), (4, 1)],
   (4, 1): [(5, 1), (4, 2)],
   (4, 2): [(5, 2), (4, 3)],
   (4, 3): [(5, 3), (4, 4)],
   (4, 4): [(5, 4), (4, 5)],
   (4, 5): [(5, 5)],
   (5, 0): [(5, 1)],
   (5, 1): [(5, 2)],
   (5, 2): [(5, 3)],
   (5, 3): [(5, 4)],
   (5, 4): [(5, 5)],
   (5, 5): []}

visited = []
path = []
routes = []


def goal_test(node):
    if node == (5, 5):
        return True
    else:
        return False


found = False


def dfs(visited, graph, node):
    global routes
    visited = visited + [node]
    if goal_test(node):
        routes = routes + [visited]
    else:
        for neighbour in graph[node]:
            dfs(visited, graph, neighbour)


dfs(visited, map, (0, 0))
print(len(routes))
for route in routes:
    print(route)

此实现采用了几种不良做法:

  • map
    是一个本机Python函数,因此使用该名称创建变量是一个坏主意

  • 已访问的
    不需要在全局范围内进行初始化:调用方对此不感兴趣,因为它只在DFS算法本身中起作用

  • routes
    也不必初始化为空列表,而且
    dfs
    变异此全局变量是不好的。相反,
    dfs
    应该将该信息返回给调用者。这使得一个
    dfs
    调用自包含,因为它返回从当前节点到目标的可能路由。调用方可以使用附加节点扩展此返回集合中的路由

  • goal\u test
    的主体应该写为
    returnnode==(5,5)
    。如果。。。else只是将布尔值转换为相同的布尔值

  • 当您只需将一个参数传递给表示目标节点的
    dfs
    函数时,函数
    goal\u test
    似乎有些过分。这也使得它更通用,因为您不需要在函数中硬编码目标位置

  • path
    found
    已初始化,但从未使用过

  • dfs
    如果图形有循环,则会遇到堆栈溢出。这不会发生在给定的图上,因为该图是非循环的,但如果在给它循环图时也可以依赖此函数,则会更好

  • dfs
    将多次访问同一单元格,因为它可以通过不同的路径找到(例如
    (2,2)
    ),因此它将从此处执行与以前相同的dfs搜索。通过存储上次访问该单元得到的结果,可以稍微提高效率,也就是说,我们可以使用备忘录。收益很小,因为大部分时间都花在创建和复制路径上。如果函数只计算路径的数量,而不构建路径,那么(使用记忆)的收益将非常显著

下面是一个处理上述各点的实现。它使用包装器函数来隐藏对调用方的备忘录使用,并减少需要传递给
dfs
的参数数量:

def search(graph, source, target):
    # Use memoization to avoid repetitive DFS from same node, 
    #  Also used to mark a node as visited, to avoid runnning in cycles
    memo = dict()  # has routes that were already collected

    def dfs(node):
        if node not in memo:  # not been here before
            if node == target:
                memo[node] = [[target]]
            else:
                # Mark with None that this node is on the current path
                #   ...avoiding infinite recursion on a cycle
                memo[node] = None  # temporary value while not yet back from recursion
                memo[node] = [
                    [node] + route 
                        for neighbour in graph[node]
                            for route in dfs(neighbour) 
                                if route
                ]
        return memo[node]

    return dfs(source)

graph = {(0, 0): [(1, 0), (0, 1)],
    # ...etc ... 
}

routes = search(graph, (0, 0), (5, 5))

print(len(routes))
for route in routes:
    print(route)

尝试将其可视化,并创建一个树形图,这将很有帮助。如果它从阴影
map
开始,它不是很好。然后,它继续混合显式的
全局(
路由
)和传递的全局(
访问
)。最后,它会找到所有路由,因为它永远不会返回-它之所以有效,是因为它不是周期性的(它不会检查访问以避免循环)。我只是对“访问”如何允许DFS继续搜索而不重复我猜?不幸的是,如果我理解了我没有得到的东西,那么我会尝试查找它,为它的模糊性道歉,我只是在逐步寻找一个解释。我看得越多,情况就越糟。我认为你应该忘记这个实现。这不好。对于其他图形,这甚至可能无限循环运行(直到堆栈溢出发生)。您是否在寻求改进?