C++实现DFS算法模板详解
作者:WeekendFlower
时间:2026-01-12
浏览:0
递归DFS需初始化visited数组并在进入前检查越界和访问状态,非递归DFS用stack模拟并压栈前标记visited,回溯DFS须成对操作状态变量且剪枝前置。
递归DFS需初始化visited数组并在进入前检查越界和访问状态,非递归DFS用stack模拟并压栈前标记visited,回溯DFS须成对操作状态变量且剪枝前置。

直接用递归实现 DFS 最简洁,但要注意栈溢出和访问标记的时机;非递归版本用 stack 模拟更可控,适合图很大或深度不确定的场景。
递归 DFS:必须初始化 visited 数组并检查边界
递归写法最符合 DFS 直观逻辑,但容易漏掉两个关键点:一是未初始化 visited 数组导致重复访问,二是没在进入递归前检查索引越界或节点合法性。
visited必须在调用 DFS 前清零(如vector),不能只在函数内声明visited(n, false) - 每次递归入口处立刻判断
if (i < 0 || i >= n || visited[i]) return;,否则可能越界访问或死循环 - 邻接表遍历时,对每个
neighbor都要先检查是否已访问,再递归——顺序不能颠倒
非递归 DFS:用 stack 存节点索引,手动管理状态
用 stack 替代系统调用栈,能避免深递归导致的栈溢出,也方便在遍历中插入调试逻辑。但需注意:它不等价于“递归的逐行翻译”,而是按压栈顺序反向访问子节点。
- 压栈前就要标记
visited[node] = true,否则同一节点可能被多次压入 - 遍历邻接表时,推荐倒序压栈(如从
adj[node].rbegin()到rend()),使出栈顺序与递归一致 - 若需记录路径或深度,可在
stack中存pair(节点 + 当前深度)
void dfs_iterative(int start, const vector>& adj) { int n = adj.size(); vector visited(n, false); stack st; st.push(start); visited[start] = true; while (!st.empty()) { int u = st.top(); st.pop(); // 处理节点 u for (auto it = adj[u].rbegin(); it != adj[u].rend(); ++it) { int v = *it; if (!visited[v]) { visited[v] = true; st.push(v); } } } }
DFS 回溯模板:用于排列、组合、棋盘问题等场景
这类 DFS 的核心不是遍历图,而是探索解空间树;必须配合「进入递归前 push/标记 → 递归返回后 pop/回退」的成对操作,否则状态污染。
path和used是典型状态变量,每次修改都必须可逆- 剪枝条件(如
if (path.size() == k))应放在递归入口处,早停节省开销 - for 循环里从
start开始(组合)还是从0开始(排列),直接影响去重逻辑
图的连通性、拓扑排序、强连通分量这些进阶用途,都建立在基础 DFS 遍历正确性的前提上。最容易被忽略的是:递归版忘记传引用导致 visited 不生效,或者非递归版把 visited 标记位置错放到出栈后——这两个错误会让算法完全失效,且不易调试。
作者最新文章
赤友清理大师
2026-09-16 17:43
南邮光擎智算团队:GaN基Micro-LED光计算芯片从理论到流片的突破
2026-09-08 18:35
多张照片怎么合成PDF文件?三种图片转PDF工具怎么选?
2026-09-03 17:04
Excel转PDF防乱版指南:在线与本地双方案及排版检查
2026-09-03 10:04
多个PDF怎么合并成一个?合并后顺序怎么检查?
2026-09-02 19:54
上一篇:
Windows清理缩略图缓存方法
热门文章
更多
精品专题
更多
Mac软件
更多
WINDOWS
更多


































