深度优先搜索(Depth-First Search,简称DFS)是一种用于遍历或搜索树或图的算法。其核心思想是从根节点开始,尽可能深地搜索每一个分支,当节点v的所在边都已被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这个过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个图就可以完全被遍历。
分享内容直达
2024最全大厂面试题无需C币点我下载或者在网页打开全套面试题已打包
AI绘画关于SD,MJ,GPT,SDXL百科全书
2024Python面试题
2024最新面试合集链接
2024大厂面试题PDF
面试题PDF版本
java、python面试题
AI Gamma一键生成PPT工具直达链接
史上最全文档AI绘画stablediffusion资料分享
AI绘画 stable diffusion Midjourney 官方GPT文档 AIGC百科全书资料收集
AIGC资料包
原理
DFS算法的工作原理基于回溯法,它使用一个栈(显式或隐式)来实现。在访问节点时,首先将所有邻接点(未被访问的)存入栈中,然后选择其中一个邻接点作为下一个要访问的节点,这个过程一直持续到没有未访问的邻接点为止。这时,算法会回溯到上一个节点,并选择另一个邻接点继续搜索,直到所有节点都被访问。
伪代码
DFS(node):
标记 node 为已访问
对于 node 的每一个未访问的邻接点 neighbor:
DFS(neighbor)
实战代码解析
以下是使用Java实现的DFS算法,用于解决LeetCode上的二叉树遍历问题(例如,题目 104. 二叉树的最大深度):
class Solution {
public int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
// 使用DFS遍历二叉树
return dfs(root, 1);
}
private int dfs(TreeNode node, int depth) {
if (node == null) {
return depth - 1; // 如果当前节点为空,返回上一层的深度
}
// 递归搜索左子树和右子树的最大深度
int leftDepth = dfs(node.left, depth + 1);
int rightDepth = dfs(node.right, depth + 1);
// 返回两个子树中的最大深度
return Math.max(leftDepth, rightDepth);
}
}
在这段代码中,maxDepth
方法首先检查根节点是否为空,如果为空则返回深度0。然后定义了一个辅助方法 dfs
,它接受当前节点和当前深度作为参数。在 dfs
方法中,如果当前节点为空,表示已经到达了叶子节点的下一层,因此返回当前的深度减1。如果当前节点不为空,则递归地对左子树和右子树调用 dfs
方法,并将深度增加1。最后,返回左子树和右子树中的最大深度。
应用场景
DFS算法在解决许多问题时都非常有用,包括但不限于:
- 拓扑排序
- 寻找连通分量
- 路径查找(如迷宫问题)
- 组合问题的求解(如全排列、组合数的生成)
- 树或图的遍历
DFS是一种非常强大的算法,它在很多面试题和实际应用中都有广泛的应用。通过理解和掌握DFS,你将能够解决许多复杂的问题。
深度优先搜索(DFS)和广度优先搜索(BFS)都是图和树的遍历算法,但它们在搜索顺序和数据结构的使用上有明显的不同。
DFS与BFS的区别
-
搜索顺序:
- DFS:沿着当前路径深入搜索,直到无法继续前进,然后回溯到上一个分叉点,继续搜索其他分支。
- BFS:逐层进行搜索,先访问离起始点最近的节点,然后是次近的节点,依此类推。
-
数据结构:
- DFS:通常使用栈(显式或隐式)来实现,可以是递归调用。
- BFS:使用队列来追踪待访问的节点。
-
内存消耗:
- DFS:通常比BFS内存消耗低,因为DFS不需要存储所有待访问的节点。
- BFS:可能需要存储所有待访问的节点,因此内存消耗可能较大。
-
应用场景:
- DFS:适用于寻找所有解的问题,路径查找,以及需要遍历所有可能情况的场景。
- BFS:适用于寻找最短路径问题,以及需要逐层处理数据的场景。
BFS算法原理
广度优先搜索(BFS)是一种按层遍历图的算法。它从根节点开始,首先访问所有邻接点,然后再逐层向外扩展,访问下一层的节点,直到访问完所有节点。
BFS伪代码
BFS(start):
创建一个队列 queue
将 start 加入 queue
标记 start 为已访问
while queue 不为空:
node = queue 取出队首元素
对于 node 的每一个未访问的邻接点 neighbor:
标记 neighbor 为已访问
将 neighbor 加入 queue
实战代码解析
以下是使用Java实现的BFS算法,用于解决LeetCode上的图遍历问题(例如,题目 102. 二叉树的层序遍历):
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<>();
if (root == null) {
return result;
}
// 创建一个队列用于BFS
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int levelSize = queue.size(); // 当前层的节点数
List<Integer> level = new ArrayList<>(); // 当前层的节点值
// 一次循环遍历当前层的所有节点
for (int i = 0; i < levelSize; i++) {
TreeNode node = queue.poll(); // 取出队首节点
level.add(node.val); // 将节点值加入当前层
// 将左右子节点加入队列,如果存在的话
if (node.left != null) {
queue.offer(node.left);
}
if (node.right != null) {
queue.offer(node.right);
}
}
result.add(level); // 将当前层的节点值加入结果列表
}
return result;
}
}
在这段代码中,我们首先检查根节点是否为空,如果为空则直接返回结果。然后创建一个队列 queue
用于BFS,并初始化队列,将根节点加入队列。在主循环中,我们首先记录当前层的节点数 levelSize
,然后创建一个列表 level
用于存储当前层的所有节点值。接着,我们循环 levelSize
次,每次从队列中取出一个节点,将其值加入 level
列表,并将该节点的左右子节点(如果存在)加入队列。最后,将 level
加入结果列表 result
。这个过程一直持续到队列为空,即所有层都被遍历完毕。
应用场景
BFS算法在解决以下类型的问题时非常有用:
- 寻找最短路径
- 确定节点间的最短距离
- 图的层序遍历
- 社交网络中的朋友关系搜索
通过理解和掌握BFS,你可以在面试和实际工作中解决许多与图遍历相关的问题。