深度优先搜索(DFS)和广度优先搜索(BFS)

一、深度优先搜索DFS和广度优先BFS的 区别:

BFS是队列的思想。

DFS是栈的思想。

 

BFS思想:

BFS是队列的思想。如下图:BFS从起点A,把A附近的点(B、C)先遍历,遍历完(B、C)入队,然后再以B为起点,遍历B点附近的未被遍历过的点。呈现扩散趋势。所以以下图为例,以A点为起点,BFS遍历的顺序是:[ A,B,C,D,E,F ]

DFS思想:

DFS是栈的思想。如下图:DFS从起点A开始,遍历顺序是:['A', 'C', 'E', 'D', 'F', 'B']。A点可以到B点和C点,所以B、C点入栈,由于栈是后进先出,所以C点出栈(被遍历),然后接着C点附近未入过栈的D、E点入栈,然后是后入栈的E点出栈(被遍历),然后接着E点附近未入过栈的点入栈,然后发现.......E点附近的点都入过栈了...怎么办呢,既然没新的点入栈,那就继续出栈,所以,D点出栈,然后D点附近未入过栈的F点入栈,如此类推....... 就会得到遍历顺序:['A', 'C', 'E', 'D', 'F', 'B']。

可以发现DFS的思想是:一路到底的,每到一个地方就先把那地方藏着,当“备胎”,一直走到没路走了,才回去找“备胎”。

所以:

1 、无论DFS和BFS是对图遍历还是对树遍历,其BFS对应队列,DFS对应栈的思想是离不开的。都得构造一个队列或栈。

(树的DFS和BFS版本:https://blog.csdn.net/u014453898/article/details/105291886

2、BFS是列表头出队(队列),DFS是列表尾出队(栈)

二、代码:

graph = {'A':set(['B','C']),
         'B':set(['A','C','D']),
         'C':set(['A','B','D','E']),
         'D':set(['B','C','E','F']),
         'E':set(['C','D']),
         'F':set(['D'])}

def bfs(graph,start):
    res = []
    visited,queue = set(),[start]
    visited.add(start)
    while len(queue)>0:
        vertex = queue.pop(0)
        nodes = graph[vertex]
        for node in nodes:
            if node not in visited:
                visited.add(node)
                queue.append(node)
        res.append(vertex)
    return res

def dfs(graph, start):
    visited, stack = set(), [start]
    res = []
    while len(stack)>0:
        vertex = stack.pop()
        if vertex not in visited:
            visited.add(vertex)
            nodes = graph[vertex]
            for node in nodes:
                if node not in visited:
                    stack.append(node)
            res.append(vertex)
    return res

print(bfs(graph,'A')) #['A', 'B', 'C', 'D', 'E', 'F']

 

额外拓展:

利用 DFS走迷宫(DFS+回溯法)

DFS在图中的作用是:在图的某一点(任何一点),都可以通过DFS遍历其他所有点。

所以通过DFS是可以遍历所有点的,那具体怎么做呢?

在当前点(i,j),通过调用 DFS(i-1,j) ,DFS(i+1,j) ,DFS(i,j-1) ,DFS(i,j+1) 向四个方向进行递归调用DFS来遍历其他点。然后在DFS中判断当前点是否为围墙(假设围墙的数值为1,路的数值为0),若是围墙,则返回,不继续调用DFS。通过这个思路就可以遍历所有图中的点。

但是,可以遍历图中所有的点,那如何返回走过的路径呢?那就要用到回溯法了。

有人说,那一边走一边用列表记录路径,当走到终点时,返回走过的路径不就行了?但这样做只能记录一条通路,如果到终点的走法有多条通路呢?那么这种做法就不可行了。所以要用到回溯法,回溯法就是进入一次递归(DFS)前记录一个点到列表中,然后递归推出时,就把这个点从列表中删去。这样就可以记录多条通路,代码如下:

import numpy as np

grid = [[0,1,1,0],[0,1,1,0],[0,1,0,0],[0,0,0,0]]
endx,endy = len(grid)-1,len(grid[0])-1 #终点坐标

used = np.zeros((len(grid),len(grid[0])),dtype='uint8')
path = []
result = []
def dfs(i,j,endx,endy,path):
    if i<0 or j<0 or i>len(grid)-1 or j>len(grid[0])-1 or used[i][j] == 1 or grid[i][j]==1:
        return
    path.append((i, j)) #记录当前位置
    if i ==endx and j==endy: #若到达终点,则返回路径
        result.append(tuple(path))
        path.remove((i,j))
        return
    used[i][j] = 1
    # 当前点向上下左右四个方向走
    dfs(i,j-1,endx,endy,path)
    dfs(i-1,j,endx,endy,path)
    dfs(i,j+1,endx,endy,path)
    dfs(i+1,j,endx,endy,path)
    used[i][j] = 0
    path.remove((i,j)) #退出记录当前位置

if __name__ == '__main__':
    dfs(0,0,endx,endy,path)
    print(np.array(grid))
    for i in result:
        print(i)
''' 两条通路
((0, 0), (1, 0), (2, 0), (3, 0), (3, 1), (3, 2), (2, 2), (2, 3), (3, 3))
((0, 0), (1, 0), (2, 0), (3, 0), (3, 1), (3, 2), (3, 3))
'''

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值