C++如何实现广度优先搜索BFS_C++图论算法路径查找实例【练习】

12次阅读

最稳妥的 c ++ bfs 实现是用 std::queue 管理节点、std::vector 记录访问状态;必须“入队即标记”,邻接表按图类型双向 / 单向建边,路径还原需维护 parent 数组并正确初始化与回溯。

C++ 如何实现广度优先搜索 BFS_C++ 图论算法路径查找实例【练习】

std::queuestd::vector 实现标准 BFS 遍历

广度优先搜索在 C++ 中最稳妥的实现方式是依赖 STL 容器:用 std::queue 管理待访问节点,用 std::vector<bool></bool>std::vector<int></int> 记录访问状态或距离。别手写队列,也别用 std::stack 混淆——BFS 的层序特性完全依赖 FIFO 行为。

常见错误是把邻接点一股脑 push 进队列却不标记已入队,导致重复入队、内存爆掉或死循环。正确做法是「入队即标记」,不是「出队才标记」。

  • 初始化时将起点入队,并设 visited[start] = true
  • 每次从队首取节点 u,遍历其所有邻接点 v
  • 对每个未访问过的 v,立刻设 visited[v] = true,再 push 入队
  • 若需记录路径长度,用 dist[v] = dist[u] + 1;若需还原路径,额外维护 parent[v] = u

邻接表建图时注意边方向与重边处理

图的存储方式直接影响 BFS 正确性。无向图要双向加边:adj[u].push_back(v)adj[v].push_back(u) 缺一不可;有向图只加单向边。如果输入含重边(相同 u→v 多次),std::vector 邻接表会存多份,但只要访问标记到位,不影响结果——只是略微拖慢常数。

别用邻接矩阵存稀疏图:10⁵ 节点时 int adj[100000][100000] 直接编译失败或 OOM。真要动态建图,用 vector<vector>></vector> 即可,空间复杂度 O(V+E)。

立即学习 C++ 免费学习笔记(深入)”;

  • 输入 N 个节点(编号 0~N-1)和 M 条边,先 vector<vector>> adj(N)</vector>
  • 读入每条边后,按图类型决定是否双向插入
  • 若题目说「可能有自环」,检查 u == v,通常跳过(避免自己访问自己)

从 BFS 到最短路径:如何还原具体路径

BFS 本身只保证首次到达某点时路径最短(无权图),但默认不保存路径细节。要输出从起点到终点的完整节点序列,必须在搜索时记录每个节点的前驱 parent[v]。终点回溯到起点后,再反转数组即可。

容易忽略的是:起点的 parent[start] 应设为 -1 或特殊值,否则回溯时无法终止;另外,若终点根本不可达,parent[end] 保持初始值(如 -1),需提前判断,否则反转空路径会 crash。

  • 声明 vector<int> parent(n, -1)</int>,起点处 parent[start] = -2 或保留 -1 并单独标记
  • 当从 u 扩展到 v 时,执行 parent[v] = u
  • 回溯时用 while (v != -1) {path.push_back(v); v = parent[v]; },最后 reverse(path.begin(), path.end())

遇到超时或 WA?检查这三处硬伤

练习中 80% 的 WA 或 TLE 来自边界疏漏,而非算法逻辑。尤其注意:节点编号是否从 0 开始?输入的边是否包含无效索引(如 N=5 却出现节点 6)?队列是否用了 int 而非 size_t 导致下标越界?

  • 读入节点数 N 后,邻接表大小必须是 adj.resize(N),不是 N+1(除非题目明确编号 1~N 且你习惯偏移)
  • queue 存的是节点编号,不是指针或结构体——别为了“省事”塞 pair<int></int> 却忘了更新逻辑
  • 多组测试用例时,每次都要清空 adj、重置 visitedparent,不能只 memset 部分内存

路径查找类题目的关键不在 BFS 框架,而在建图与回溯的衔接是否干净。一个没初始化的 parent 数组,比算法写错更难调试。

text=ZqhQzanResources