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 水坑计数

相关推荐
动词ing10 小时前
【题目练习】旋转图像
算法
天疆说10 小时前
【无标题】
算法
GG.WinGel10 小时前
三元组中心问题
java·数据结构·算法·青少年编程·蓝桥杯
开开心心就好10 小时前
电脑小说阅读器,支持朗读和自定义皮肤
服务器·开发语言·javascript·算法·pdf·c#·音视频
闻缺陷则喜何志丹11 小时前
【c++20】协程与屏障
c++·算法·c++20·携程·屏障
erzong23111 小时前
Linux操作系统:线程池&踩坑修复
linux·运维·算法
alphaTao11 小时前
LeetCode 每日一题 2026/10/19-2026/10/25
算法·leetcode
ZhengEnCi12 小时前
一亿条数据取前100条完全指南:从全量排序到分块流式最小堆的4种解法实测
python·算法·排序算法
zaizai100712 小时前
STL深度剖析2
java·c++·算法
数智奔流13 小时前
MiniMax的低价攻势,撞上“背题”疑云
前端·javascript·算法