S型层序遍历是奇数层(根为第0层)从左到右、偶数层从右到左的层序遍历;需每层动态翻转访问顺序,不可最后整体reverse;推荐用vector缓存本层值后按level%2决定是否reverse,并用std::move避免拷贝。

什么是S型层序遍历(Zigzag Level Order Traversal)
它不是简单地从左到右逐层输出,而是奇数层(根为第0层)从左到右,偶数层从右到左,形成“之”字形。关键在于每层节点的访问顺序要动态翻转,不能靠最后对结果数组整体 reverse —— 那样会破坏层内逻辑,也掩盖了真实遍历过程。
用 std::queue + std::vector 模拟双端行为
标准 std::queue 只支持 FIFO,但 S 型需要某一层“倒着进、正着出”或“正着进、倒着出”。最稳妥的做法是:每层先用 std::vector 缓存该层所有节点值,再根据层数奇偶性决定是否调用 std::reverse;或者更高效地,在插入时就控制方向:
- 层数为偶数(0, 2, 4…):用
push_back正向添加 - 层数为奇数(1, 3, 5…):用
insert(result[level].begin(), val)或提前预留空间后反向赋值
推荐前者——逻辑清晰、不易越界。注意:不要在遍历过程中修改正在使用的 queue,必须用临时容器暂存下一层节点。
避免常见错误:nullptr 处理与空树边界
如果直接对 root == nullptr 返回空 std::vector<:vector>></:vector>,没问题;但若忘记在循环中判 node->left 和 node->right 是否为空,就会触发解引用空指针。正确写法是:
立即学习“C++免费学习笔记(深入)”;
if (node->left) q.push(node->left); if (node->right) q.push(node->right);
另外,别把层数变量 level 放在 while 外部并每次 ++,否则最后一层结束后 level 多加了一次,影响翻转判断。应在每层处理前确定当前 level,并在本层结束后再递增。
完整可跑片段的关键骨架
核心结构如下,不依赖额外类或智能指针,专注逻辑主干:
std::vector<std::vector<int>> zigzagLevelOrder(TreeNode* root) {
if (!root) return {};
std::vector<std::vector<int>> result;
std::queue<TreeNode*> q;
q.push(root);
int level = 0;
<pre class="brush:php;toolbar:false;">while (!q.empty()) {
int size = q.size();
std::vector<int> level_vals;
for (int i = 0; i < size; ++i) {
TreeNode* node = q.front(); q.pop();
level_vals.push_back(node->val);
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
if (level % 2 == 1) {
std::reverse(level_vals.begin(), level_vals.end());
}
result.push_back(std::move(level_vals));
++level;
}
return result;}
真正容易被忽略的是 std::move 的使用——它避免了 vector 的深层拷贝,在层数多、节点值多时有实际性能差异;还有就是 level % 2 == 1 这个判定,有人习惯写成 level & 1,语义等价但可读性略低,除非明确追求位运算优化。


















