C++怎么实现图的遍历_C++DFS BFS教程【算法】

8次阅读

dfs递归溢出因未控深度、图大或有环且未标记访问;须用visited数组防无限递归;邻接表优选vector,超大编号用unordered_map;非递归dfs可避栈溢出。

C++怎么实现图的遍历_C++DFS BFS教程【算法】

DFS 递归写法为什么栈溢出?

因为没控制递归深度,或者图太大、有环但没标记访问状态。c++ 默认栈空间小,深递归直接崩。

  • 必须用 visited 数组/集合标记已访问节点,否则无限递归
  • 邻接表用 vector<vector>></vector>vector<list>></list> 更快,缓存友好
  • 若图节点编号不连续或范围极大(比如 1e9),改用 unordered_map<int vector>></int> 存图,但 visited 也得用 unordered_set
  • 手动模拟栈的 DFS(非递归)能避开栈溢出,但代码稍长:用 stack<int></int> + while 循环 + 显式压栈/弹栈

BFS 用 queue 还是 deque

日常用 queue 就够了;只有需要从队首插入(比如 0-1 BFS)才换 deque。别为“听起来更通用”滥用 deque

  • queue 底层默认是 deque,性能无差别;选它语义更清晰
  • 别用 vector 手搓队列——pop_front() 是 O(n),BFS 复杂度直接升到 O(n²)
  • 如果要记录层数(比如最短路径长度),在每轮 while 前用 int size = q.size() 固定当前层宽度,别边遍历边 pushsize()
  • 多源 BFS(如多个起点同时出发)只需初始把所有起点 push 进队,逻辑不变

邻接表 vs 邻接矩阵:图稀疏时别硬用二维数组

点数 1e4、边数 1e4 的图,用 vector<vector>></vector> 开 1e4×1e4 内存就爆了(100MB+),而且遍历效率低。

  • 稀疏图(边数 ≈ 点数)必用邻接表:vector<vector>> graph(n)</vector>
  • 邻接矩阵只适合点数 ≤ 1e3 且需频繁查「u 到 v 是否有边」的场景;查边用 graph[u][v] 是 O(1),但初始化和遍历都是 O(n²)
  • 如果边带权且稀疏,邻接表存 vector<vector int>>></vector>,第二项是权重;别为了省事全用 map 嵌套,常数大
  • 无向图加边记得双向:graph[u].push_back(v)graph[v].push_back(u)

DFS/BFS 返回值怎么设计才不踩坑?

别让函数既遍历又返回布尔值判断连通性,又塞路径结果——职责混在一起,调试时根本分不清哪步挂了。

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

  • 单纯遍历:函数 void dfs(int u, vector<bool>& visited, const vector<vector>>& graph)</vector></bool>,副作用修改 visited
  • 查连通性:单独写 bool isConnected(int start, int target, ...),内部调用 DFS/BFS,末尾返回 visited[target]
  • 要路径:BFS 天然支持,用 vector<int> parent</int> 记前驱,找到终点后倒推;DFS 要回溯,路径存在 vector<int> path</int> 里,进递归 push_back,出递归 pop_back
  • 全局变量(如 pathfound)必须重置,尤其写在类里多次调用时,别忘了在入口清空

实际写的时候,图结构本身不难,真正卡住的往往是边界没判、标记没设、容器类型选错、或者把搜索逻辑和业务逻辑揉太死。这些地方一松懈,debug 花的时间比写代码还长。

text=ZqhQzanResources