您的位置:首页 >C++实现深度优先搜索(DFS)求路径 _ 邻接表表示与递归【源码】
发布于2026-05-03 阅读(0)
扫一扫,手机访问

说起来,DFS记录路径的核心,其实就围绕着一个容器和一个动作:维护好那个path容器,并在回溯时及时把节点弹出来。当然,不是所有DFS都需要记录具体路径,但一旦你的需求是输出从A点到B点的完整路线,这个“进栈-出栈”的节奏就至关重要了。忘了弹出节点?那path里就会混杂不同分支的“脚印”,最终得到的路径要么长度诡异,要么根本就不是你想要的。
常见的翻车现场包括:路径里出现了毫不相干的节点;明明存在通路却搜索不到;或者得到的路径长度和预期对不上。
std::vector来存路径,简单直观,下标天然反映了访问顺序。const std::vector>& graph 和当前节点u作为参数传进去,避免不必要的拷贝开销。u == target,还得加上对visited数组的判断,防止在环里打转。要论轻便高效,std::vector绝对是首选。直接用节点编号(假设是0到n-1)作为索引,访问起来飞快。除非节点编号极其稀疏且不连续,否则别轻易动用std::map——它带来的键值查找开销和额外的判空逻辑,在遍历时都是负担。
建表时得留心方向:有向图只加一条边graph[u].push_back(v);如果是无向图,那就得双向添加。另外,如果输入数据习惯从1开始计数,一个好习惯是读入后立刻统一转成0-indexed,这样后续所有数组操作都会安全得多。
立即学习“C++免费学习笔记(深入)”;
graph.resize(n)设定大小,比循环里push_back空向量要高效。graph的结构,否则很容易打乱整个搜索逻辑。std::vector>> ,把邻接点和权重打包存放。标准的DFS会不辞劳苦地探索所有可能,但在很多实际场景里——比如找个迷宫出口、或者解析任务依赖——我们往往只要任意一条可行路径就足够了。这时候,光靠递归函数里的return可不够,它只能结束当前层的调用,控制不了整个递归栈。正确的做法,是引入一个“哨兵”——一个布尔类型的引用变量found。
典型的错误是在找到目标后直接return,结果上层递归还在继续尝试其他分支。而正确的逻辑是,在每一层递归开始都先检查一下if (found) return,一旦找到路径,就立即把found设为true,然后层层返回。
bool dfs(int u, int target, std::vector& path, std::vector& visited, bool& found) 。path,然后设置found = true并返回true。true,就能立刻拿到路径,无需等待整个递归树遍历完毕。这个问题背后通常有两个“元凶”:要么是递归深度太大(比如节点数超过10^5),超出了默认栈空间的承受能力;要么就是图里存在环,而visited数组没有正确更新,导致搜索陷入了无限递归。C++的默认栈空间并不大,深度达到1e5量级时,栈溢出几乎是必然的。
visited数组,并且在访问每个新节点前严格执行if (visited[u]) return。-O2或许能提升一些性能,但它解决不了算法本身的逻辑缺陷。static int depth = 0; depth++; if (depth > 1000) { /* 输出日志 */ },快速定位是不是递归过深了。说到底,记录路径的代码本身并不复杂,真正的挑战在于保持递归过程中状态的“洁净”,在各种边界条件下统一控制流程,以及在大规模数据面前守住性能和资源的底线。这些细节如果当时没写清楚,下次维护代码时,很可能还会在同一个地方再摔一跤。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
9