简述深度优先搜索遍历的方法。

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简述深度优先搜索遍历的方法。相关的知识,希望对你有一定的参考价值。

简述深度优先搜索遍历的方法?深度优先搜索算法(Depth-First-Search, DFS),最初是一种用于遍历或搜索树和图的算法,在LeetCode中很常见,虽然感觉不难,但是理解起来还是有点难度的。

简要概括,深度优先的主要思想就是“不撞南墙不回头”,“一条路走到黑”,如果遇到“墙”或者“无路可走”时再去走下一条路。

思路
假如对树进行遍历,沿着树的深度遍历树的节点,尽可能深的搜索树的分支,当达到边际时回溯上一个节点再进行搜索。如下图的一个二叉树。


首先给出这个二叉树的深度优先遍历的结果(假定先走左子树):1->2->4->5->3->6->7

那是怎样得到这样的结果呢?
根据深度优先遍历的概念:沿着这树的某一分支向下遍历到不能再深入为止,之后进行回溯再选定新的分支。

定义节点

class TreeNode
int val;
TreeNode left;
TreeNode right;

递归的方式

分别对左右子树进行递归,一直到底才进行回溯。如果不了解递归可以参考我的博客你真的懂递归吗?。

class Solution
public void depthOrderTraversalWithRecusive(TreeNode root)
if(root == null)
return;

System.out.print(root.val +"->");
depthOrderTraversalWithRecusive(root.left);
depthOrderTraversalWithRecusive(root.right);


迭代的方式

上面实现了递归方式的深度优先遍历,也可以利用栈把递归转换为迭代的方式。

但是为了保证出栈的顺序,需要先压入右节点,再压左节点。

class Solution
public void depthOrderTraversalWithoutRecusive(TreeNode root)
if(root == null) return;
Stack<TreeNode> stack = new Stack<>();
stack.push(root);
while(!stack.isEmpty())
TreeNode node = stack.pop();
System.out.print(node.val + "->");
if(node.right != null)
stack.push(node.right);

if(node.left != null)
stack.push(node.left);




接着再列举个利用深度优先遍历的方式的题目

扫雷
给定一个表示游戏板的二维字符矩阵,'M'表示一个未挖出的地雷,'E'表示一个未挖出的空方块,'B' 代表没有相邻(上,下,左,右,和所有4个对角线)地雷的已挖出的空白方块,数字('1' 到 '8')表示有多少地雷与这块已挖出的方块相邻,'X' 则表示一个已挖出的地雷。

根据以下规则,返回相应位置被点击后对应的面板:

如果一个地雷('M')被挖出,游戏就结束了- 把它改为'X'。
如果一个没有相邻地雷的空方块('E')被挖出,修改它为('B'),并且所有和其相邻的方块都应该被递归地揭露。
如果一个至少与一个地雷相邻的空方块('E')被挖出,修改它为数字('1'到'8'),表示相邻地雷的数量。
如果在此次点击中,若无更多方块可被揭露,则返回面板。
示例

输入:

[['E', 'E', 'E', 'E', 'E'],
['E', 'E', 'M', 'E', 'E'],
['E', 'E', 'E', 'E', 'E'],
['E', 'E', 'E', 'E', 'E']]

Click : [3,0]

输出:

[['B', '1', 'E', '1', 'B'],
['B', '1', 'M', '1', 'B'],
['B', '1', '1', '1', 'B'],
['B', 'B', 'B', 'B', 'B']]
思路:根据给定的规则,当给定一个Click坐标,当不为雷的时候以此坐标为基点向四周8个方向进行深度遍历,把空格E填充为B,并且把与地雷M相连的空方块标记相邻地雷的数量。

注意 :



在这个题中可以沿着8个方向递归遍历,所有要注意程序中,采用了两个for循环可以实现向8个方向递归。
参考技术A 深度优先遍历类似于数的先序遍历,是树的先序遍历的推广。
1.从图中某个顶点v出发,访问v。找到刚访问过得顶点的第一个未被访问的邻接点,访问该顶点。
2.以该顶点为新顶点,重复此步骤,直至刚访问的顶点没有未被访问的邻接点为止。
3.返回前一个访问过得且扔有未被访问的邻接点的顶点,找到该顶点的下一个未被访问的邻接点,访问该顶点。
重复步骤2,3,直至图中所有顶点都被访问。
参考技术B 简述深度优先搜索遍历的方法。深度优先遍历从某个顶点出发,首先访问这个顶点,然后访问该顶点的第一个未被访问的邻结点,以此邻结点为顶点继续访问,同时记录其余未访问的邻接点,当一个顶点的所有邻接点都被访问时,回退一个顶点,将未访问的邻接点作为顶点,重复此步骤,直到所有结点都被访问完为止。

广度优先遍历从某个顶点出发,首先访问这个顶点,然后找出这个结点的所有未被访问的邻接点,访问完后再访问这些结点中第一个邻接点的所有结点,重复此方法,直到所有结点都被访问完为止。
深度优先遍历的主要思想就是:首先以一个未被访问过的顶点作为起始顶点,沿当前顶点的边走到未访问过的顶点,当没有未访问过的顶点时,则回到上一个顶点,继续试探访问别的顶点,直到所有的顶点都被访问过。显然,深度优先遍历是沿着图的某一分支遍历直到末端,然后回溯,再沿着另一条边进行同样的遍历,直到所有的顶点都被访问过为止。

广度优先遍历的思想就是:首先以一个未被访问的顶点,访问其所有的相邻的顶点,然后对每个相邻的顶点,再访问他们相邻的未被访问过的顶点,直到所有的顶点都被访问过,遍历结束。更适用于所有边的权重相同的情况。

深度优先搜索

深度优先搜索也叫DFS。是一种常见的图搜索(遍历)方法。该方法秉承着不到黄河心不死的思路对图中个点进行遍历搜索。

思想:

  先沿着一条路遍历(查询)直到这条路不能走的时候,我们再回退到可以走位置继续遍历(查询)

方法(不给详细代码给思路,具体问题有增减很正常):

  首先我们遍历的是一个图。G(V,E),G代表该图,V是点的集合,E是边的集合。

  1.递归的:

    函数1:

      1.建立一个数组保存所有点的状况。(是否被遍历过)

      2.建立一个数组保存每个点遍历的顺序(就是一个int数组记录第一个点是第几个被遍历的,或者hashMap用点名和他的顺序一一对应)。

      3.建立代表初始编号的变量并初始化为1(2,3步如果不在乎顺序可以不用操作)

      4.遍历每个点,如果该点没有被访问过,就对该点调用函数2(你可能会想肯定都没有访问过啊,但是在调用函数2时会访问部分后续的节点)

    函数2:

      1.标记调用点已访问(记录在状态数组中)

      2.记录该点的为第几个遍历的,然后使记录顺序的变量加1(结合函数1看是否需要)

      3.如果该点是查询的点输出信息并停止(遍历就无视这步)

      4.对该点的所有未被访问(就是你没有在状态数组中标记的)的邻接点调用函数2

  2.非递归的我们使用栈来储存只用一个函数就可以了

    函数3:

      1.建立一个栈来储存点

      2.同样需要状态数组

      3.记录编号的数组同上

      4.初始编号为1(3,4依然随情况决定要还是不要)

      2.将第一个点压入栈中(没有要求就随意取一个点)

      3.当栈不为空时循环做以下的操作(缩进表示循环)

        4.将栈首元素出栈,如果要查询就检查该点与需要查询的点是否一致,一致就停止。不需要的话就只出栈。

        5.将该点标记为已访问,记录其编号。

        6.将其所有的没有访问的邻接点压入栈中。

      

  时间复杂度;

        1.使用临接矩阵O(n^2),因为在寻找临接点这步操作的时候临接矩阵会查看所有的点

        2.使用临接表O(n+e)因为所有定点的临接点之和就相当于两倍的边。n+2e属于O(n+e)

以上是关于简述深度优先搜索遍历的方法。的主要内容,如果未能解决你的问题,请参考以下文章

深度优先搜索法和广度优先搜索法

简述深度优先搜索

基本算法——深度优先搜索(DFS)和广度优先搜索(BFS)

数据结构与算法图遍历算法 ( 深度优先搜索 DFS | 深度优先搜索和广度优先搜索 | 深度优先搜索基本思想 | 深度优先搜索算法步骤 | 深度优先搜索理论示例 )

图的深度优先搜索

深度优先搜索