力扣刷题#26-0102-二叉树的层序遍历

力扣刷题#26-0102-二叉树的层序遍历

题目

给你二叉树的根节点 root,返回其节点值的层序遍历(即逐层地、从左到右访问所有节点)。

输入: root = [3,9,20,null,null,15,7]
    3
   / \
  9  20
     / \
    15  7
输出: [[3],[9,20],[15,7]]

前置知识:BFS vs DFS

中序遍历(DFS)是一条路走到黑再回头。层序遍历(BFS)是一层一层扫过去——像剥洋葱,从外往里。

        1          ← 第0层
       / \
      2   3        ← 第1层
     / \   \
    4   5   6      ← 第2层
       /
      7            ← 第3层

BFS 输出: [[1], [2,3], [4,5,6], [7]]

BFS 的核心工具是队列——从队头拿一个节点出来,把它的左右孩子塞到队尾。先进先出,天然就是一层一层走。


我的思路

BFS 的基本骨架

queue<TreeNode*> q;
q.push(root);

while (队列不空) {
    取出队头
    把孩子入队
}

但这样只能把所有节点串成一个长列表 [1,2,3,4,5,6,7],分不出"哪几个是第一层、哪几个是第二层"。

分层的诀窍:sz = q.size()

在每一轮 while 循环开始时,队列里的节点全部属于同一层。取一次 q.size() 存成 sz,然后用 for 循环恰好处理 sz 个节点。循环内新入队的孩子不会影响 sz——天然的"这一层"和"下一层"隔离。

while (队不空) {
    int sz = q.size();       // ← 这一层有几个
    vector<int> level;

    for (int i = 0; i < sz; i++) {   // 只取 sz 个
        弹出队头 → 记录值
        有左孩子 → 入队
        有右孩子 → 入队
    }
    res.push_back(level);    // 这一层收工
}

走一遍

        3
       / \
      9  20
         / \
        15  7
轮次 sz 队列(处理前) 处理的节点 level 队列(处理后)
1 1 [3] 3 [3] [9,20]
2 2 [9,20] 9, 20 [9,20] [15,7]
3 2 [15,7] 15, 7 [15,7] []

结果:[[3], [9,20], [15,7]]


我的 AC 代码

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if (!root) return {};

        vector<vector<int>> res;
        queue<TreeNode*> q;
        q.push(root);

        while (!q.empty()) {
            int sz = q.size();
            vector<int> level;

            for (int i = 0; i < sz; i++) {
                TreeNode* cur = q.front();
                q.pop();
                level.push_back(cur->val);
                if (cur->left)  q.push(cur->left);
                if (cur->right) q.push(cur->right);
            }
            res.push_back(level);
        }
        return res;
    }
};

代码逐段解析

第 3 行:空树保护

if (!root) return {};

力扣会传 root = nullptr 的测试用例。没有这行,q.push(nullptr) 之后取出 cur = nullptr,取 cur->val 就直接崩了。

第 6-7 行:初始化

queue<TreeNode*> q;
q.push(root);

根节点入队,一切从这里开始。

第 9 行:外层 while

while (!q.empty()) {

队列不空 = 还有层没处理完。

第 10-11 行:分层核心

int sz = q.size();
vector<int> level;

sz 必须在 for 循环之前取一次。如果写成 for(i=0; i<q.size(); i++),循环里 push 了新节点,q.size() 会持续变大 → 死循环或结果错乱。

第 13-18 行:处理当前层

for (int i = 0; i < sz; i++) {
    TreeNode* cur = q.front();
    q.pop();
    level.push_back(cur->val);
    if (cur->left)  q.push(cur->left);
    if (cur->right) q.push(cur->right);
}

for 循环跑完,当前层的所有节点都取出来了,它们的值进了 level,孩子们进了队列——成为"下一层"。

第 19 行:收尾

res.push_back(level);

一层完事,塞进结果。


踩坑记录

坑 1:空树没判

// ❌
q.push(root);  // root = nullptr
// ...
level.push_back(cur->val);  // cur = nullptr → 崩

修复if (!root) return {}; 放在最前面。

坑 2:sz 没提前存

// ❌
for (int i = 0; i < q.size(); i++) { ... }   // q.size() 在循环里会变

修复int sz = q.size(); 在 for 外面取一次。


复杂度分析

维度 说明
时间复杂度 O(n) 每个节点入队一次、出队一次
空间复杂度 O(n) 队列最大存一整层节点

关键点总结

关键点 说明
核心结构 队列——先入先出,天然适配层序遍历
分层的技巧 sz = q.size() 在 for 前取一次,循环内新入队不影响
BFS 模板 while(队不空) { sz取一次; for(0..sz) { 弹出+记录+孩子入队 } }
空树保护 if (!root) return {};

本文档由 AI 辅助生成,作者提供问题,思路和代码,AI仅负责文本修饰,综合获得以上内容。

posted @ 2026-08-05 11:59  STA_running  阅读(6)  评论(0)    收藏  举报