DFS递归必须用visited数组/集合标记已访问节点,否则在无向图或有环图中会无限递归导致栈溢出;标记需在递归前完成,邻接表建图时无向图要双向加边,节点编号不连续时需先校验。

DFS 递归实现必须处理访问标记
不加 visited 数组或集合,DFS 会在无向图或有环图里无限递归——哪怕只有两个点互相连接,也会栈溢出。C++ 里没有运行时栈深警告,错误表现常是 Segmentation fault (core dumped),而不是清晰的异常。
- 用
vector<bool></bool>或unordered_set<int></int>记录已访问节点,索引从 0 开始就优先选前者(更快、更省内存) - 标记必须在进入递归前做:
visited[u] = true;,不能放在递归调用之后 - 如果图带权或需要路径还原,额外维护
parent或path数组,但别和visited混用同一容器
邻接表建图时注意边方向与重复边
用 vector<vector>></vector> 存无向图,每条边要双向添加;有向图只加一次。漏掉方向,DFS 走不到目标节点,调试时容易误以为算法写错了。
- 输入是边列表时,循环里写两遍
graph[u].push_back(v);和graph[v].push_back(u);才算无向 - 重边(相同 u→v 多次出现)一般不影响 DFS 正确性,但会让邻接表变大,降低缓存友好性;可提前用
set去重,不过多数 OJ 数据不卡这个 - 节点编号不连续?别直接用
graph[u],先确认u ,否则触发 <code>std::out_of_range
非递归 DFS 要手动模拟栈并避免重复压栈
用 stack<int></int> 实现迭代版 DFS,常见错误是把未访问节点反复压入栈中——比如在 while 循环里对每个邻居都 push,却不检查 visited,结果一个节点被多次处理。
- 正确顺序:取栈顶 → 标记已访问 → 遍历邻居 → 对每个「未访问」邻居执行
push - 和递归版相比,迭代版的访问顺序可能不同(取决于压栈顺序),但连通性判断结果一致
- 若需记录 DFS 序(如时间戳),迭代写法里要在 pop 时打时间戳,不是 push 时;否则序号不反映实际访问顺序
DFS 判断连通性 vs 找路径:返回值设计差异
单纯问“能不能到”,函数返回 bool 最干净;但一旦要返回具体路径,别用全局 vector + 回溯,容易在多组测试中残留数据。
立即学习“C++免费学习笔记(深入)”;
- 找路径推荐传引用参数:
bool dfs(int u, int target, vector<int>& path)</int>,找到就立刻 return true 并结束所有递归层 - 避免在递归出口处清空
path,应在每次递归返回前pop_back()(回溯) - 如果图很大而路径很短,早停比遍历全图更重要;没加 early-return 的 DFS 可能超时,尤其在稀疏图中
边界情况比想象中多:空图、单点、自环、孤立点——这些都不该让 DFS 崩溃,但容易在 visited 初始化或邻接表大小上出错。











