谁能解释深度优先搜索的这种实现方式?

问题描述

因此,我目前正在学习搜索算法,如果有人可以提供关于深度优先搜索的实现方式的解释,我将不胜感激,但我确实了解深度优先搜索的工作原理一种算法,但是我在努力了解如何在这里实现它。

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

map = {(0,0): [(1,0),(0,1)],1): [(1,1),2)],2): [(1,2),3)],3): [(1,3),4)],4): [(1,4),5)],5): [(1,(1,0): [(2,1): [(2,2): [(2,3): [(2,4): [(2,5): [(2,(2,0): [(3,1): [(3,2): [(3,3): [(3,4): [(3,5): [(3,(3,0): [(4,1): [(4,2): [(4,3): [(4,4): [(4,5): [(4,(4,0): [(5,1): [(5,2): [(5,3): [(5,4): [(5,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,neighbour)


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

解决方法

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

  • map是Python的本机功能,因此使用该名称创建变量是个坏主意。

  • visited不需要在全局范围内初始化:调用者对此没有兴趣,因为它仅在DFS算法本身中发挥作用

  • routes也不必初始化为空列表,并且dfs突变此全局变量是很糟糕的。相反,dfs应该将该信息返回给呼叫者。这使得一个dfs调用是独立的,因为它返回了从 current 节点到目标的可能路由。调用方可以使用其他节点扩展此返回的集合中的路由。

  • goal_test的正文应写为return node == (5,5)if ... else只是将布尔值转换为相同的布尔值。

  • 当您只需将参数传递给表示目标节点的goal_test函数时,函数dfs似乎是过大的。这也使它变得更加通用,因为您无需在函数内对目标位置进行硬编码。

  • pathfound已初始化但从未使用过。

  • 如果图具有循环,则
  • 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,(5,5))

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