2020-09-10

时间:2020-9-15 作者:admin

Maze试验台的设计与实现(宽度优先搜索和深度优先搜索的理解)

一、 宽度优先搜索

BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。在一棵树上的搜索特点就是由根节点向深层逐层搜索,搜索完一层后再搜索下一层;在图中搜索方式类似于“波浪“,由根节点一层一层的向外搜索。
用队列实现宽度优先算法:
1、把根节点放到队列中。
2、每次从队列的头部取出一个元素v。判断节点v是否被访问:一、当节点v没有被访问时,执行步骤3、4、。二、v节点被访问时,则不需要对节点v进行任何操作,重复步骤2。
3、对于没有被访问的节点v要进行以下几个操作:一、判断当前节点v是否是目标goal,若是则返回目标,搜索结束。二、节点v不是目标节点,则将节点v标记为已访问,并将v的所有孩子节点集合w放在队列的末尾(对于一个图来说,则是与之相邻的上下四个节点)。注:对于v的孩子节点入队列前,加一个判断,将那些已访问或者是障碍物的孩子节点剔除)。
4、如果遍历整个树还没有找到,结束程序

def BFS(maze,v,goal,came_from):
    frontier=Queue()#声明一个队列
    frontier.enqueue(v)#将根节点v入队列尾
    came_from[v]=None#根节点的父节点为空
    while not frontier.is_empty():
        v=frontier.dequeue()#从队列头弹出一个节点
        if maze[v[0],v[1]]==Maze.EMPTY:#在v节点是已被访问或者是障碍物的时候,都无意义可直接跳过
            if v==goal:
                return v
            else:
                maze[v[0],v[1]]==Maze.OCCUPIED#当该节点不是目标节点时,将其标记为已访问,并将其子节点入队列尾
                for w in Maze.getAllMoves(v[0],v[1]):#Maze.getAllMoves()方法是获得与v节点相邻的所有节点
                    if w==Maze.EMPTY:#有选择的入队列,排除无意义的节点(必要性:***一定要剔除已被访问的节点,否则v扩展w入队列,然后w出队列,同时又同样的扩展v,从而进入死循环v,w不停地出入队列。***
                        frontier.enqueue(w)
                        came_from[w]=v
    return None

二、深度优先搜索

顾名思义,深度优先,则是以深度为准则,先一条路走到底,直到达到目标。也就是递归下去。否则既没有达到目标又无路可走了,那么则退回到上一步的状态,走其他路,这便是回溯上来。

递归实现

def DFS(maze,v,goal,came_from):
    if came_from=={}:
        came_from[v]=None
    if v==goal:
        return v
    maze[v[0],v[1]]==Maze.OCCUPIED
    for w in maze.getAllMOves(v[0],v[1]):
        if maze[w[0],w[1]]==Maze.EMPTY:
            came_from[w]=v
            result=DFS(maze,w,goal,came_from)
            if result==goal:
                return result
    return None

用栈实现

与宽度优先搜索很类似,但又有些差异。宽度是越深层的节点越后访问,所以先来的节点先访问,用队列储存;而深度优先搜索则相反,先来的节点后访问,所以用栈来储存。

def DFS(maze,v,goal,came_from):
    stack=Stack()
    stack.push(v)
    came_from[v]=None#根节点的父节点为空
    while not stack.is_empty():
        v=stack.pop()
        if maze[v[0],v[1]]==Maze.EMPTY:#在v节点是已被访问或者是障碍物的时候,都无意义可直接跳过
            if v==goal:
                return v
            else:
                maze[v[0],v[1]]=Maze.OCCUPIED#当该节点不是目标节点时,将其标记为已访问,并将其子节点入栈尾
                for w in maze.getAllMoves(v[0],v[1]):
                    if maze[w[0],w[1]]==Maze.EMPTY:#v的子节点有可能已被访问或者是障碍物,需判断。删除后程序卡死,为什么?
                        stack.push(w)            #关键在于有已被访问的节点入栈由v扩展出w,v出栈;然后访问w的时候,再由w扩展出v,因为v和w是相邻关系, v再入栈,这样就会形成死循环
                        came_from[w]=v
    return None

总结:深度优先搜索与宽度优先搜索之间的不同在分别用栈与队列实现的时候非常明显,归结为一点就是给节点赋予的优先级不同。

声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。