C++用std::queue实现BFS层序遍历的核心是每次外层循环前记录q.size()作为本层节点数,再用for循环精确处理该数量节点;入队前必须检查子节点非空,根为空时直接返回空vector。

用 std::queue 实现标准 BFS 层序遍历
核心就是维护一个先进先出的队列,每次取队首节点,访问它,再把它的左右子节点(非空)依次入队。C++ 标准库的 std::queue 天然适配这个逻辑,不需要手写队列。
关键点在于:必须在每轮循环开始前记录当前队列长度,即本层节点数,否则无法区分层界。
- 错误写法:
while (!q.empty()) { auto node = q.front(); q.pop(); /* 立即 push 左右子节点 */ }—— 这样会导致下层节点混入当前层处理,无法按层分组 - 正确做法:用
int levelSize = q.size()固定本层宽度,内层循环只处理levelSize个节点 - 示例片段:
std::queue<TreeNode*> q;<br>q.push(root);<br>while (!q.empty()) {<br> int n = q.size();<br> for (int i = 0; i < n; ++i) {<br> auto node = q.front(); q.pop();<br> result.push_back(node->val);<br> if (node->left) q.push(node->left);<br> if (node->right) q.push(node->right);<br> }<br>}
需要按层分组返回时,怎么组织 vector<vector>></vector>
很多题目(比如 LeetCode 102)要求返回二维数组,每层一个子向量。这时候不能只用一个扁平的 result 向量,而要在每轮外层循环中新建一个临时向量。
- 每次内层
for循环前声明vector<int> level</int>,在循环中level.push_back(node->val) - 内层结束后,把
level整体push_back到最终结果ans中 - 注意边界:如果
root == nullptr,直接返回空vector<vector>></vector>,别忘了判空 - 性能影响:多一次 vector 构造和移动,但现代 C++ 的 RVO 和 move 语义基本无感
遇到空节点或 NULL 指针报错怎么办
TreeNode* 是裸指针,解引用前不检查 nullptr 就会崩溃,常见错误是忘记判断 node->left 或 node->right 是否为空就直接 q.push(node->left)。
立即学习“C++免费学习笔记(深入)”;
- 错误:
q.push(node->left);—— 如果node->left是nullptr,虽然能 push,但后续 pop 出来后解引用会段错误 - 正确:只对非空子节点操作 ——
if (node->left) q.push(node->left); - 更安全的习惯:所有对
node->xxx的访问前,先确保node != nullptr;队列中永远只存有效指针 - 调试技巧:在
q.front()后加一句assert(node != nullptr);,快速定位空指针来源
想用 std::deque 或自己实现队列行不行
可以,但没必要。std::queue 默认底层就是 std::deque,接口更清晰、语义更明确;自己写链表或数组模拟队列容易引入边界错误,且无实际收益。
-
std::queue提供front()、pop()、push(),完全覆盖 BFS 需求 - 用
std::deque手动管理的话,得自己调用front()+pop_front()+push_back(),代码更啰嗦,可读性反而下降 - 唯一可能换容器的场景:极端内存受限且确定最大节点数,改用循环数组优化,但普通题目毫无必要
实际写的时候最容易漏的是层内计数和空指针检查,尤其是嵌套结构里多一层判断就容易跳过。只要守住「每次只处理当前层固定数量节点」和「所有指针解引用前必判空」这两条,BFS 就不会跑飞。


















