用queue实现bfs层序遍历的核心是每次外层循环前记录队列当前大小levelsize作为本层节点数,再用for循环精确处理这levelsize个节点,从而严格分层;需判空节点再入队,空树须显式返回空vector。

用 queue 实现 BFS 层序遍历,核心是记录每层节点数
直接用 std::queue 做 BFS 没问题,但“分层”意味着每轮循环必须明确处理完当前层所有节点,不能混进下一层。关键不是靠节点值或空指针判断边界,而是每次进入内层循环前,先记下队列当前长度——这恰好是本层剩余节点数。
常见错误是只用一个 while (!q.empty()) 循环,然后在循环里盲目 q.pop() + q.push(),结果导致层与层之间无法区分,输出变成一维扁平序列。
- 每次外层循环开始时,执行
int levelSize = q.size(); - 用
for (int i = 0; i 固定迭代次数,确保只处理本层节点 - 内层循环中每 pop 一个节点,就把它的左右子节点(非空)push 进队列,这些新节点属于下一层,不会影响本次
levelSize
TreeNode 结构和空节点处理要一致
如果用 nullptr 表示空子节点,那在 push 前必须判空,否则队列里塞入 nullptr 会导致后续访问 ->left 崩溃。标准做法是:只 push 非空子节点。
有人尝试把 nullptr 当作层分隔符(类似 BFS 中插入哨兵),但容易出错——比如根为空时队列初始就含 nullptr,或连续两层都无子节点时哨兵位置混乱。不推荐。
if (node->left) q.push(node->left);if (node->right) q.push(node->right);- 不要写
q.push(node->left)不加判断
返回二维 vector 的典型写法
每层结果存进一个 vector<int></int>,再把该 vector push 到外层 vector<vector>></vector>。注意内存局部性:内层 vector 在每次 for 循环结束时自动构造完成,无需提前 reserve(除非已知每层大致规模)。
示例片段:
vector<vector>> levelOrder(TreeNode* root) {
vector<vector>> res;
if (!root) return res;
queue<treenode> q;
q.push(root);
while (!q.empty()) {
int levelSize = q.size();
vector<int> level;
for (int i = 0; i val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
res.push_back(level);
}
return res;
}</int></treenode></vector></vector>
性能和边界情况提醒
时间复杂度仍是 O(n),但空间上 queue 最坏存满一层节点——完全二叉树最后一层约 n/2 个节点,所以空间复杂度 O(n),不是 O(log n)。这点常被忽略。
真正容易漏掉的是空树输入:root == nullptr 时要立刻返回空 vector,否则后续 q.push(root) 虽不崩溃,但循环体一次都不进,结果正确但逻辑不健壮;更糟的是有人忘了判空,直接访问 root->val 导致段错误。
- 务必在函数开头检查
if (!root) return {}; - 不要依赖 queue 为空来隐式处理空树,显式判空更安全
- 如果题目要求每层从右到左(如之字形),只需把
level.push_back(...)改成level.insert(level.begin(), ...)或最后 reverse,但别在 BFS 主干里改遍历顺序逻辑
分层的关键永远在 levelSize 快照,其余都是围绕它组织的细节。写熟了就不再纠结“怎么分层”,而专注节点处理本身。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











