2023年6月29日发(作者:)
图⽂详解DFS算法和BFS算法点击关注上⽅“五分钟学算法”,设为“置顶或星标”,第⼀时间送达⼲货。转⾃ 码海前⾔深度优先遍历(Depth First Search, 简称 DFS) 与⼴度优先遍历(Breath First Search)是图论中两种⾮常重要的算法,⽣产上⼴泛⽤于拓扑排序,寻路(⾛迷宫),搜索引擎,爬⾍等,也频繁出现在 leetcode,⾼频⾯试题中。本⽂将会从以下⼏个⽅⾯来讲述深度优先遍历,⼴度优先遍历,相信⼤家看了肯定会有收获。深度优先遍历,⼴度优先遍历简介习题演练DFS,BFS 在搜索引擎中的应⽤深度优先遍历,⼴度优先遍历简介深度优先遍历深度优先遍历主要思路是从图中⼀个未访问的顶点 V 开始,沿着⼀条路⼀直⾛到底,然后从这条路尽头的节点回退到上⼀个节点,再从另⼀条路开始⾛到底...,不断递归重复此过程,直到所有的顶点都遍历完成,它的特点是不撞南墙不回头,先⾛完⼀条路,再换⼀条路继续⾛。树是图的⼀种特例(连通⽆环的图就是树),接下来我们来看看树⽤深度优先遍历该怎么遍历。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,所以此时会遍历 73、从 7 往上回溯到 3, 1,发现 1 还有节点 4 未遍历,所以此时沿着 4, 8 进⾏遍历,这样就遍历完成了完整的节点的遍历顺序如下(节点上的的蓝⾊数字代表)相信⼤家看到以上的遍历不难发现这就是树的前序遍历,实际上不管是前序遍历,还是中序遍历,亦或是后序遍历,都属于深度优先遍历。那么深度优先遍历该怎么实现呢,有递归和⾮递归两种表现形式,接下来我们以⼆叉树为例来看下如何分别⽤递归和⾮递归来实现深度优先遍历。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) { = value; = left; = right; } } public static void dfs(Node treeNode) { if (treeNode == null) { return; } // 遍历节点 process(treeNode) // 遍历左节点 dfs(); // 遍历右节点 dfs(); }}递归的表达性很好,也很容易理解,不过如果层级过深,很容易导致栈溢出。所以我们重点看下⾮递归实现2、⾮递归实现仔细观察深度优先遍历的特点,对⼆叉树来说,由于是先序遍历(先遍历当前节点,再遍历左节点,再遍历右节点),所以我们有如下思路1. 对于每个节点来说,先遍历当前节点,然后把右节点压栈,再压左节点(这样弹栈的时候会先拿到左节点遍历,符合深度优先遍历要求)2. 弹栈,拿到栈顶的节点,如果节点不为空,重复步骤 1, 如果为空,结束遍历。我们以以下⼆叉树为例来看下如何⽤栈来实现 DFS。整体动图如下整体思路还是⽐较清晰的,使⽤栈来将要遍历的节点压栈,然后出栈后检查此节点是否还有未遍历的节点,有的话压栈,没有的话不断回溯(出栈),有了思路,不难写出如下⽤栈实现的⼆叉树的深度优先遍历代码:/** * 使⽤栈来实现 dfs * @param root */public static void dfsWithStack(Node root) { if (root == null) { return; } Stack> bfsWithBinaryTreeLevelOrderTraversal(Node root) { if (root == null) { // 根节点为空,说明⼆叉树不存在,直接返回空数组 return (); } // 最终的层序遍历结果 List
> result = new ArrayList<>(); Queue
from collections import deque que = deque([root]) #队列,保存待处理的节点 while len(que)!=0: lev = [] #列表,保存该层的节点的值 thislevel = len(que) #该层节点个数 while thislevel!=0: head = t() #弹出队⾸节点 #队⾸节点的左右孩⼦⼊队 if is not None: () if is not None: () () #队⾸节点的值压⼊本层 thislevel-=1 (lev) return res这题⽤ BFS 是显⽽易见的,但其实也可以⽤ DFS, 如果在⾯试中能⽤ DFS 来处理,会是⼀个⽐较⼤的亮点。⽤ DFS 怎么处理呢,我们知道, DFS 可以⽤递归来实现,其实只要在递归函数上加上⼀个「层」的变量即可,只要节点属于这⼀层,则把这个节点放⼊相当层的数组⾥,代码如下:private static final List> TRAVERSAL_LIST = new ArrayList<>();/** * leetcdoe 102: ⼆叉树的层序遍历, 使⽤ dfs * @param root * @return */private static void dfs(Node root, int level) { if (root == null) { return; } if (TRAVERSAL_() < level + 1) { TRAVERSAL_(new ArrayList<>()); } List
发布者:admin,转转请注明出处:http://www.yc00.com/news/1687983196a63604.html
评论列表(0条)