最直观解法是用 std::queue 控制层序遍历、std::stack 临时存储下层节点顺序:偶数层子节点 left→right 入栈,奇数层 right→left 入栈,每层结束批量压入 queue;或改用 std::deque,front() 读取、按层数奇偶选 push_back()/push_front() 写入,但需预存当前层大小防计数干扰。

用 std::queue + std::stack 混合实现最直观
核心思路是:奇数层从左到右,偶数层从右到左,但不用在遍历中反复翻转 vector——那样做 push_back 多次再 reverse,时间浪费在复制上。更稳的做法是用一个 std::stack 临时存下一层节点的访问顺序。
实际操作时,用 std::queue 控制当前层节点出队,同时按「当前层是否为偶数层」决定子节点入栈/入队顺序:
- 若当前层索引为偶数(第 0、2、4… 层),子节点按
left→right顺序压入std::stack - 若当前层索引为奇数(第 1、3、5… 层),子节点按
right→left顺序压入std::stack - 每处理完一层,把
stack中所有节点一次性转移到queue,作为下一层输入
这样避免了 vector 翻转,也规避了双端队列 std::deque 的边界判断开销。
std::deque 双端插入可省掉栈,但要注意方向控制
如果想少维护一个容器,直接用 std::deque<treenode></treenode> 替代 queue + stack 组合,可行,但必须严格区分「读取端」和「写入端」:
立即学习“C++免费学习笔记(深入)”;
- 读取始终从
front()取(模拟 BFS 的 FIFO) - 写入则根据层数奇偶性选择:
push_back()(偶数层子节点正序)或push_front()(奇数层子节点倒序) - 每层结束前需记录当前
dequesize,否则边 pop 边 push 会干扰计数
注意:push_front() 在 std::deque 上虽是常数复杂度,但比 push_back() 稍慢;频繁调用可能影响性能,尤其树宽较大时。
递归解法容易错在层索引传递和容器复用
有人尝试用 DFS + vector<vector>></vector> 存每层结果,最后对偶数索引层调用 std::reverse。这看似简洁,但有两个隐藏坑:
- 层索引(depth)必须显式传参,不能靠递归调用栈深度推断——因为左右子树递归顺序固定(先左后右),会导致同一层节点插入顺序混乱
- 如果复用同一个
vector并用res[depth].push_back(val),必须确保res.size() > depth,否则越界;常见写法是提前res.resize(max_depth)或每次检查if (res.size() - 最终翻转只应在所有 DFS 完成后统一做,不能在递归中边插边翻,否则破坏层内顺序
这种写法代码短,但调试时容易漏掉 resize 或 depth 传错,线上环境不如迭代稳定。
LeetCode 测试用例里最常卡住的是空树和单节点
写完别急着提交,先手动过两组边界:
- 输入为
nullptr→ 输出应为vector<vector>>{}</vector>(空 vector),不是{{}} - 输入为单节点(如
new TreeNode(1))→ 输出应为{{1}},注意不要因初始化逻辑多塞一层空 vector - 层序输出中每层 vector 不能为空(除非整棵树为空),否则 OJ 判为格式错误
很多实现会在初始化时 push 一个空 vector 进结果,或者 while 循环前没判 root 是否为空,导致结果多出一个空层——这个细节不打日志很难发现。


















