用std::queue实现二叉树bfs层序遍历的最简结构是:先判空根节点,再入队root;每轮while循环前用q.size()冻结当前层节点数n,内层for循环执行n次,每次pop、访问值、非空子节点入队;空指针绝不入队,确保安全解引用。

用 queue 实现 BFS 层序遍历的最简结构
直接用 std::queue 配合节点指针就能跑通,不需要额外标记或递归。核心是每次处理“当前层所有节点”,靠循环次数控制——不是靠节点自身存层数。
常见错误是只 push 一次 root 就开始 while 循环,却没在循环内区分层边界,导致输出乱序或漏节点。
- 初始化时只 push 根节点:
q.push(root) - 每轮 while 循环前先记录队列大小
int n = q.size(),这个n就是当前层节点数 - 用 for 循环执行
n次 pop + 处理 + push 子节点,保证本层全出、下层全进 - 空节点不入队(
if (node->left) q.push(node->left))
遇到 nullptr 时怎么安全访问子节点
二叉树节点常为 TreeNode* 类型,root 可能为 nullptr,必须在进入主循环前判空,否则 q.push(nullptr) 后 pop 出来再解引用会崩溃。
典型错误现象:Segmentation fault (core dumped) 或 VS 中报 Access violation。
- 入口处加
if (!root) return {}; - 每次从队列 pop 出节点后,立刻检查是否为
nullptr,再访问left/right - 不要把
nullptr压入队列——即使想占位也得另写逻辑(如 LeetCode 的序列化需求),标准 BFS 不需要
如何按层分组返回结果(vector>)
如果要返回每层一个 vector,关键是在 for 循环内把本层节点值暂存进临时 vector,循环结束后再 push 到结果里。
容易踩的坑是把 res.push_back({val}) 写在内层循环里,结果变成每个节点一行;或者忘记清空临时容器,导致数据累积。
vector<vector>> levelOrder(TreeNode* root) {
if (!root) return {};
vector<vector>> res;
queue<treenode> q;
q.push(root);
while (!q.empty()) {
int n = 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); // ← 整层处理完才 push
}
return res;
}
</int></treenode></vector></vector>
为什么不用 stack 或 deque(除了 front/back 操作)
std::queue 是最自然的选择:BFS 要求先进先出,而 std::stack 是后进先出,会变成 DFS;std::deque 虽支持 front/pop_front,但接口冗余,且易误用 push_front 破坏顺序。
性能上,std::queue 默认基于 std::deque,但封装后语义清晰,不易出错。有人用 vector 模拟队列(pop 时 erase(0)),那是 O(n) 操作,完全不可取。
- 坚持用
std::queue<treenode></treenode>,别自己造轮子 - 避免混用
deque::push_back和deque::front—— 接口虽可用,但意图模糊,review 时难快速确认逻辑 - 指针类型选
TreeNode*而非TreeNode&:队列不能存引用,且需支持空值判断
实际写的时候,最容易被忽略的是那个 int n = q.size() 必须在 for 循环外获取——如果把它放进 for 条件里,每次迭代都重新求 size,就会把刚 push 进去的下层节点也算进来,导致提前结束或无限循环。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











