深度优先遍历(DFS)和广度优先遍历(BFS)
深度优先遍历(DFS)和广度优先遍历(BFS)
图的遍历:所谓遍历,即是对结点的访问。一个图有多个结点,如何遍历这些结点,有两种访问策略:
深度优先遍历
(Depth First Search, 简称 DFS)广度优先遍历
(Breadth First Search 简称 BFS)
开发中广泛用于拓扑排序,寻路(走迷宫),搜索引擎,爬虫等
一、深度优先遍历
1.1 主要思路
从图中一个未访问的顶点 V 开始,沿着一条路一直走到底,然后从这条路尽头的节点回退到上一个节点,再从另一条路开始走到底…,不断递归重复此过程,直到所有的顶点都遍历完成,它的特点是不撞南墙不回头,先走完一条路,再换一条路继续走。
1.2 实现过程
树是图的一种特例(连通无环的图就是树),接下来我们来看看树用深度优先遍历该怎么遍历。
1、我们从根节点 1 开始遍历,它相邻的节点有 2,3,4,先遍历节点 2,再遍历 2 的子节点 5,然后再遍历 5 的子节点 9。
2、上图中一条路已经走到底了(9是叶子节点,再无可遍历的节点),此时就从 9 回退到上一个节点 5,看下节点 5 是否还有除 9 以外的节点,没有继续回退到 2,2 也没有除 5 以外的节点,回退到 1,1 有除 2 以外的节点 3,所以从节点 3 开始进行深度优先遍历,如下:
3、同理从 10 开始往上回溯到 6, 6 没有除 10 以外的子节点,再往上回溯,发现 3 有除 6 以外的子点 7,所以此时会遍历 7。
3、从 7 往上回溯到 3, 1,发现 1 还有节点 4 未遍历,所以此时沿着 4, 8 进行遍历,这样就遍历完成了。
完整的节点的遍历顺序如下(节点上的的蓝色数字代表):
树的前序遍历,实际上树的前序遍历、中序遍历、后序遍历,都属于深度优先遍历。
1.3 深度优先遍历的实现
递归和非递归两种表现形式,接下来我们以二叉树为例来看下如何分别用递归和非递归来实现深度优先遍历。
1.3.1 递归实现
递归实现比较简单,由于是前序遍历,所以我们依次遍历当前节点,左节点,右节点即可,对于左右节点来说,依次遍历它们的左右节点即可,依此不断递归下去,直到叶节点(递归终止条件),代码如下:
public class Solution { private static class Node { public int value; //节点值 public Node left; //左节点 public Node right; //右节点public Node(int value, Node left, Node right) { this.value = value; this.left = left; this.right = right; } } public static void dfs(Node treeNode) { if (treeNode == null) { return; } // 遍历节点 process(treeNode) // 遍历左节点 dfs(treeNode.left); // 遍历右节点 dfs(treeNode.right); } }
递归的表达性很好,也很容易理解,不过如果层级过深,很容易导致栈溢出。所以我们重点看下非递归实现。
具体示例查看树一章案例中的Tree类中的 preOrder(Node localRoot) 方法
1.3.2 非递归实现
对二叉树来说,由于是先序遍历(先遍历当前节点,再遍历左节点,再遍历右节点),我们可以通过栈
来实现非递归
实现思路
压栈:对于每个节点来先遍历当前节点,然后把右节点压栈,再压左节点(这样弹栈的时候会先拿到左节点遍历,符合深度优先遍历要求)。
弹栈:拿到栈顶的节点,如果节点不为空,重复步骤 , 如果为空,结束遍历。
栈实现 DFS
栈实现的二叉树的深度优先遍历代码:
/** * 使用栈来实现 dfs * @param root */ public static void dfsWithStack(Node root) { if (root == null) { return; } Stack<Node> stack = new Stack<>(); // 先把根节点压栈 stack.push(root); while (!stack.isEmpty()) { Node treeNode = stack.pop(); // 遍历节点 process(treeNode) // 先压右节点 if (treeNode.right != null) { stack.push(treeNode.right); } // 再压左节点 if (treeNode.left != null) { stack.push(treeNode.left); } } }
用栈实现深度优先遍历不用会象递归那样层级过深导致的栈溢出问题
具体示例查看树一章案例中的Tree类中的displayTree 方法
二、广度优先遍历
2.1主要思路
广度优先遍历,指的是从图的一个未遍历的节点出发,先遍历这个节点的相邻节点,再依次遍历每个相邻节点的相邻节点。
2.2 实现过程
树的广度优先遍历每个节点的值即为它们的遍历顺序。所以广度优先遍历也叫层序遍历,先遍历第一层(节点 1),再遍历第二层(节点 2,3,4),第三层(5,6,7,8),第四层(9,10)。
队列实现BFS
2.3 代码:
/** * 使用队列实现 bfs * @param root */ private static void bfs(Node root) { if (root == null) { return; } Queue<Node> stack = new LinkedList<>(); stack.add(root); while (!stack.isEmpty()) { Node node = stack.poll(); System.out.println("value = " + node.value); Node left = node.left; if (left != null) { stack.add(left); } Node right = node.right; if (right != null) { stack.add(right); } } }
具体示例查看树一章案例中的Tree类中的BFS方法
深度优先遍历(DFS)和广度优先遍历(BFS)相关推荐
- 数据结构与算法(7-2)图的遍历(深度优先遍历DFS、广度优先遍历BFS)(分别用邻接矩阵和邻接表实现)
目录 深度优先遍历(DFS)和广度优先遍历(BFS)原理 1.自己的原理图 2.官方原理图 一.邻接矩阵的深度优先遍历(DFS) 1.原理图 2. 过程: 3.总代码 二.邻接表的深度优先遍历(DFS ...
- 树的前序、中序、后序遍历及深度优先算法DFS、广度优先算法BFS及python实现
刷Leetcode时遇到一种经典数据结构--树,树是典型递归思想来的,学习树有助于学习递归思想以及栈.队列(后续细说),本文对树的结构.遍历算法以及Python实现做总结,以供复习拓展 树是连通的无环 ...
- 图的遍历(深度优先遍历DFS,广度优先遍历BFS)以及C语言的实现
遍历的定义: 从已给的连通图中某一顶点出发,沿着一些边访遍图中所有的顶点,且使每个顶点仅被访问一次,就叫做图的遍历,它是图的基本运算. 一:深度优先遍历(DFS) 1,在访问图中某一起始顶点V后,由V ...
- 一文搞定深度优先搜索(DFS)与广度优先搜索(BFS)【含完整源码】
写在前面:博主是一位普普通通的19届双非软工在读生,平时最大的爱好就是听听歌,逛逛B站.博主很喜欢的一句话花开堪折直须折,莫待无花空折枝:博主的理解是头一次为人,就应该做自己想做的事,做自己不后悔的事 ...
- 图的深度优先搜索(DFS)和广度优先搜索(BFS)算法
深度优先(DFS) 深度优先遍历,从初始访问结点出发,我们知道初始访问结点可能有多个邻接结点,深度优先遍历的策略就是首先访问第一个邻接结点,然后再以这个被访问的邻接结点作为初始结点,访问它的第一个邻接 ...
- 【蓝桥杯】2015决赛A组 5 穿越雷区(深度优先搜索dfs、广度优先搜索bfs)
历届试题 穿越雷区 问题描述 X星的坦克战车很奇怪,它必须交替地穿越正能量辐射区和负能量辐射区才能保持正常运转,否则将报废. 某坦克需要从A区到B区去(A,B区本身是安全区,没有正能量或负能量特征), ...
- 数据结构-图的深度优先遍历(DFS)和广度优先遍历(BFS)算法分析
https://www.cnblogs.com/qzhc/p/10291430.html 最后一个广度优先有错误,H不指向E,只有G指向E,所以顺序应该是ABCFDHGE
- 【数据结构与算法】2.深度优先搜索DFS、广度优先搜索BFS
原文链接:https://blog.csdn.net/qq_41681241/article/details/81432634 总结 一般来说,广搜常用于找单一的最短路线,或者是规模小的路径搜索,它的 ...
- 深度优先搜索(DFS)和广度优先搜索(BFS)探究
附BFS解题代码: #include<iostream> #include<queue> using namespace std;char room[23][23]; int ...
- 数据结构(廿五) -- C语言版 -- 图 - 图的遍历 -- 邻接矩阵 - 深度/广度优先遍历/搜索(DFS、BFS)
内容预览 零.读前说明 一.概 述 二.深度优先遍历(DFS) 2.1.无向图的遍历过程 2.2.有向图的遍历过程 2.3.总结说明 2.4.实现源代码 三.广度优先遍历(BFS) 3.1.广度优先的 ...
最新文章
- Microsoft Visual C++ 14.0 is required. Get it with “Microsoft Visual C++ Build Tools解决方案
- 【计算理论】上下文无关语法 ( 语法组成 | 规则 | 语法 | 语法示例 | 约定的简写形式 | 语法分析树 )
- Acer 4750 安装黑苹果_授人以渔的黑苹果安装教程
- JS的编码:escape,encodeURI,encodeURIComponent,解码:unescape,decodeURI,decodeURIComp
- 开发一个简单的工具,导出github仓库所有issue列表
- jQuery 事件 - bind() 方法
- 遵义大数据中心项目工程概况_市委书记张新文到曹州云都大数据中心等项目现场调研建设情况...
- 互联网金融爬虫怎么写-第二课 雪球网股票爬虫(正则表达式入门)
- 自定义view imageviw
- Git 删除本地分支和远程分支
- 根据坐标采色修改背景
- mybatis中获取当前时间_MySQL NOW和SYSDATE函数:获取当前时间日期
- wlop2020全奖励包_【图包】WLOP鬼刀壁纸【更新至2020年10月】
- 比吸烟还可怕的九大“爱好”
- 如何找短视频素材?这些工具可以帮到你
- 年轻人的第一台挂灯:米家显示器挂灯
- ABAP BTE增强举例
- 微信小程序_文档_05_框架_组件_插件_多线程_兼容_优化
- 三.字符设备驱动高级
- 电影院座位推荐--字节青训营