这两周陷入了测试和作业的漩涡中,今天才有时间坐在电脑前码字了。好吧,我承认我是在找借口了QAQ
- 引入
- 介绍
- DFS
- BFS
- 应用
- DFS应用一:二叉树中的遍历
- DFS应用二:岛屿问题
- BFS应用一:二叉树的层序遍历
- BFS应用二:图的BFS
- BFS应用三:岛屿问题
引入
DFS
(Depth First Search) 即深度优先搜索,而提到DFS
就得说起BFS
(Breadth First Search) 广度优先搜索 了
在我的上一篇文章 二叉树的引入 当中,我有提到 二叉树的前序、中序、后序遍历本质和DFS
相同,而层序遍历本质和BFS
相同,那么,DFS
和BFS
又是什么呢,怎么去实现它们呢~
来看看我在百科上看到的图,是和这次谈到的内容有关的哦~
自然界中的宽搜
介绍
DFS
假如去游玩一个市里面的景点,从景点0
开始:
DFS的介绍
要去玩这些景点有很多种方式,那怎样才算是DFS
呢~
这里先给出
DFS
的概念
深度优先搜索 简单来说就是 先深入探索,走到头再回退来寻找其他路径继续,以此反复 的遍历方式
也就是说,它可以是这样去走的:
DFS的介绍
拿二叉树举例来说可以是这样走的(二叉树的前序遍历):
二叉树的DFS
那如果不是二叉树呢,而是在一个图中呢,就比如一个二维数组中:
二维数组
又怎么走完这个图中的灰色部分呢?
首先依照遍历二维数组的方式,总可以找到第一个灰色部分,然后从这个灰色部分开始 深入探索
因为是要走完所有的灰色部分,所以很显然要先探索与之相邻的四个方框(当然,不符合就直接return
啦~):
图的BFS
再然后像之前走完所有符合的路径就像下面这个样子了:
图的BFS
细心的读者可能会发现,因为是要探索与之相邻的四个方框,那么到下一相邻方框时岂不是要返回重新来过一遍,这里先将这个疑问放着,等介绍算法实现部分再来解释吧~
BFS
而BFS
简单来说就是 一层一层由内而外 的遍历方式
那么,又怎么通过BFS
的方式来走完上面的景点呢,它可以是这样走的:
BFS的介绍
对于二叉树来说差不多是这样走的(二叉树的层序遍历):
二叉树的层序遍历
那如果是在一个二维数组中呢,与DFS
又有什么不同呢?
它也是从一个方框依次向周围探索,与DFS
区别不是很大,直接上图:
二维数组的BFS
相信到这里朋友们对于
DFS
和BFS
是怎样走的应该了解了,那么接下来该说说它们的应用及算法实现了
应用
DFS应用一:二叉树中的遍历
DFS
在二叉树中的遍历概括起来就是使用递归:
1 | 复制代码void dfs(TreeNode node) { |
然后根据遍历父结点的顺序分为了前序、中序、后序遍历(这里不深入探讨了)
DFS应用二:岛屿问题
由 m*n 个小方块组成的网格上(每一个小方块都与周围四个相邻,可以参考上文),在这样的网格上进行搜索
空头说感觉不太好说,不如直接拿道题出来说说吧~
比如在这道题中:
1
表示陆地,0
表示水域(目的是遍历完陆地的部分):
岛屿的周长
在上文也提到 从一个小方格要去探索周围四个方格,以此来走完所有陆地的部分
首先要注意的是边界的问题:
1 | 复制代码void dfs(int[][] grid, int r, int c){ |
另外要注意的就是上面留下的疑问了:遍历过的网格如何确定它遍历过没有,这样就不至于卡在死循环里
题目中是用数值来表示陆地和水域,那么可以改变遍历过的网格 的数值(当然,这个值别是0
、1
就好),以此来判断它走没走过,是不是很巧妙 :D
最后实现起来大抵是这样:
1 | 复制代码void dfs(int[][] grid, int r, int c){ |
除了上述两种应用较多外,还有其他的问题大抵上也都是用的 回溯 的思想
这里提到了 回溯 :从一条路往前走,能进则进,不能进则退回来,换一条路再试 或者说 自后向前,追溯曾经走过的路径
而想要实现 回溯,可以利用 栈 的先入后出的特性,也可以采用 递归 的方式,而递归本身就是基于方法调用栈来实现的
而相对的,
BFS
的实现关键在于 重放,也就是 将遍历过的结点按之前的遍历顺序重新回顾,可以利用队列的先入先出的特性来实现。说那么多 不如来看看下面的例子吧~
BFS应用一:二叉树的层序遍历
BFS
在二叉树中的遍历使用队列:
1 | 复制代码void bfs(TreeNode node){ |
相比于DFS
,BFS
就显得比较繁琐了,这是因为 递归 隐含的使用了系统的 栈,而我们就不需要自己维护一个数据结构了
除此之外,两者遍历结点的顺序也不同
BFS应用二:图的BFS
图的BFS
与层序遍历类似,同样需要使用队列,它的代码框架大概时这样的:
1 | 复制代码Queue<TreeNode> queue = new ArrayDeque<>(); |
上面的岛屿问题也可以用
BFS
来实现,也与上面的图的BFS
类似
BFS应用三:岛屿问题
图的BFS
同样的,0
表示海洋,1
表示陆地,从陆地依次向外遍历
BFS
又是如何实现探索周围四个方块,这里可以用两个数组来间接实现:
1 | 复制代码void bfs(int[][] grid){ |
另外还需要队列来实现BFS
,最后大概是这样子的:
1 | 复制代码void bfs(int[][] grid){ |
感觉自己的输出效率蛮低的,可能还是不太会写博客吧,不过我会坚持下去的:D
本文转载自: 掘金