dfs深度优先搜索

图片截图:

一、DFS 核心思想

从根进入,向下走,走到底,向上走;绕树一圈,最后从根退出。 本质:递归 + 系统栈

  • 向下递归时:压栈
  • 递归返回回溯时:弹栈

系统栈保存:返回地址、局部变量、函数参数。

二、四个触发时机(⭐最重要,对应 4 处 printf)

复制代码
void dfs(int u, int fa){
    printf("入 %d\n",u);  // 【1.入】刚访问到u,第一次碰到这个节点(自顶向下,算子)
    for(auto v : e[u]){
        if(v==fa) continue;
        printf("下 %d\n",u);  //【2.下】准备走向子节点v之前,可以多次执行!
        dfs(v, u);
        printf("回 %d\n",u);  //【3.回】从子节点v递归返回之后,可以多次执行!
    }
    printf("离 %d\n",u);  //【4.离】u的所有子节点全部遍历完成,即将离开u(自底向上,算父)
}

✅ 一句话区分

  1. 入(进入节点)每个节点只会触发 1 次 刚到达 u,第一次访问。做自顶向下的计算(父传给子)
  2. 下(下走,准备进子节点)每个子分支触发一次,可以多次 在循环里,每准备访问一个孩子 v 就执行一次。u 有几个子节点,就执行几次
  3. 回(回来,子节点回溯完毕)每个子分支触发一次,可以多次 子树dfs(v)全部跑完,回到 u 的时候执行。u 有几个子节点,就执行几次
  4. 离(离开节点)每个节点只会触发 1 次 u 所有子节点全部遍历结束,准备退出 u。做自底向上的计算(子结果传回父)

口诀:1 入,2 下,3 回,4 离

  • 入、离:每个节点仅一次
  • 下、回:有多少个子节点,就执行多少次(多次触碰同一节点)

计算方向

  • 自顶向下:入、下,父亲把信息传给儿子
  • 自底向上:回、离,儿子算完结果传回父亲(子算父)

三、树的 DFS vs 图的 DFS

1)树 DFS(无环,用父节点 fa 判断,不用 vis 数组)

复制代码
void dfs(int u, int fa){
    for(auto v:e[u]){
        if(v == fa) continue; // 不走回父节点
        dfs(v,u);
    }
}
  • fa:记录 u 的父节点,防止往回走。树没有环,不需要 vis 标记。

2)图 DFS(有环!必须 vis 标记)

图存在回边,只靠 fa 不够,要用vis[]记录节点是否已经访问过 ,避免死循环,遍历生成DFS 树

复制代码
int vis[N];
void dfs(int u){
    vis[u]=true; //标记已访问(入的时候标记)
    for(auto v:e[u]){
        if(vis[v]) continue;
        dfs(v);
    }
}

DFS 树:对图做深度优先遍历,遍历过程经过的边构成一棵树,原图剩下的边叫回边(红色打叉的边,不会进 DFS 树)

四、递归与系统栈原理

递归本质靠系统栈自动维护状态:

  • 向下走(递归调用子节点):压栈,保存当前函数现场
  • 走到叶子无法继续:开始回溯
  • 向上返回(递归结束):弹栈,恢复现场,执行

五、简单例子理解次数(拿第一张图的树)

节点5有 3 个子节点:2,6,7

  • 入:节点 5,1 次
  • 下:准备去 2、准备去 6、准备去 7 → 3 次下
  • 回:从 2 回来、从 6 回来、从 7 回来 → 3 次回
  • 离:全部子树走完,离开节点 5,1 次

所以:下和回是在 for 循环内部,循环几次,就跑几次;入和离在循环外面,每个节点一次。

六、什么时候在哪写代码(做题经验)

  1. :记录节点深度、标记访问、初始化节点信息(父→子传值)
  2. :进入子树前预处理,保存当前状态
  3. :子树计算完成,收集子节点结果(子→父汇总,树形 DP 最常用!)
  4. :节点全部子树处理完,计算当前节点最终信息、回溯撤销标记(回溯题)

七、易错点总结

  1. 树 dfs 参数fa,图 dfs 用vis数组,不要混用。
  2. 下、回在 for 循环内,多次执行;入、离在循环外,每个节点仅一次。
  3. 图遍历会产生 DFS 树,原图中没有被选进 DFS 树的边,是回边。
  4. 递归深度太大容易栈溢出(系统栈容量有限),大数据量要手写栈实现迭代版 DFS。

题目1 迷宫方案数

题目2 跳马方案数

题目3 八皇后

题目4 水坑计数

相关推荐
OYYHXPJR1 小时前
【算法】区间重叠模板和矩形重叠模板
算法
shehuiyuelaiyuehao1 小时前
算法46,分治快排,排序数组
java·算法·排序算法·排序
远航计算机1 小时前
GEO 选题从哪来?用一份 Query 词库把一年内容排出来
大数据·人工智能·算法·aigc
宣宣猪的小花园.1 小时前
【机器学习】神经网络与表征:为什么深度学习能自动提取特征
人工智能·嵌入式硬件·算法·机器学习
mmmmath_32 小时前
LeetCode.018.四数之和
数据结构·算法·leetcode
AIGCmagic社区2 小时前
腾讯混元 AuK 技术报告拆读:1.5B 统一语音生成与编辑,蒸馏后 4 步无 CFG 提速 4.5 倍
人工智能·算法·aigc·ai多模态
大熊背2 小时前
基于照明色度表征的颜色恒常性的白平衡算法实现
算法·白平衡·色温·色度坐标·普朗克曲线
高亦真2 小时前
今天是学习嵌入式的第38天
linux·学习·算法
Zane19942 小时前
冒泡、选择、插入排序都是O(n²),希尔排序凭什么说自己能更快
算法·排序算法