leetcode 102二叉树的层序遍历

cpp 复制代码
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        if (root == nullptr) {
            return {};
        }

        vector<vector<int>> ans;
        queue<TreeNode*> q;

        q.push(root);

        // 外层 while:一层一层处理
        while (q.empty() == false) {

            // 当前这一层节点数量
            int n = q.size();

            // 每一层都重新创建一个 layer
            vector<int> layer;

            // 内层 while:处理当前这一层的 n 个节点
            while (n != 0) {

                // 取出队头节点
                TreeNode* node = q.front();
                q.pop();

                // 当前节点加入当前层
                layer.push_back(node->val);

                // 当前层还剩一个节点少处理
                n--;

                // 把下一层节点加入队列
                if (node->left != nullptr) {
                    q.push(node->left);
                }

                if (node->right != nullptr) {
                    q.push(node->right);
                }
            }

            // 当前层处理完毕
            ans.push_back(layer);
        }

        return ans;
    }
};

这段代码的整体思路就是:

用一个队列 queue 做层序遍历,每次先记住"当前层有多少个节点",然后把这一层的节点全部取出来,同时把它们的左右孩子放进队列。这样下一轮处理的就是下一层。

假设二叉树是:

复制代码
        3
       / \
      9   20
         /  \
        15   7

最终希望得到:

复制代码
[
    [3],
    [9, 20],
    [15, 7]
]

先看代码:

复制代码
vector<vector<int>> ans;
queue<TreeNode*> q;
q.push(root);

这里:

复制代码
ans

负责保存最终答案。

复制代码
q

负责保存"接下来要处理的节点"。

最开始:

复制代码
q = [3]
ans = []

然后进入外层循环:

复制代码
while(q.empty() == false)

意思是:

只要队列里面还有节点,就继续处理。

第一次进入外层循环时:

复制代码
q = [3]

创建当前层:

复制代码
vector<int> layer;

所以:

复制代码
layer = []

然后:

复制代码
int n = q.size();

此时:

复制代码
n = 1

这个 n 非常关键。

它表示:

当前这一层有 1 个节点。

所以接下来:

复制代码
while(n != 0)

就是把当前这一层的 1 个节点全部处理掉。


第一层

当前:

复制代码
q = [3]
n = 1
layer = []

执行:

复制代码
TreeNode* node = q.front();

那么:

复制代码
node -> 3

然后:

复制代码
layer.push_back(node->val);

得到:

复制代码
layer = [3]

然后:

复制代码
q.pop();

把 3 从队列删除:

复制代码
q = []

然后:

复制代码
n--;

得到:

复制代码
n = 0

接着检查 3 的左右孩子:

复制代码
if(node->left != nullptr){
    q.push(node->left);
}

if(node->right != nullptr){
    q.push(node->right);
}

3 的左右孩子是:

复制代码
9
20

所以放入队列:

复制代码
q = [9, 20]

注意这里非常重要。

虽然现在:

复制代码
q = [9,20]

但是:

复制代码
n = 0

所以:

复制代码
while(n != 0)

结束。

这意味着:

9、20 虽然已经进入队列,但是它们属于下一层,所以这一轮先不处理。

然后:

复制代码
ans.push_back(layer);

得到:

复制代码
ans = [
    [3]
]

第二层

又回到:

复制代码
while(q.empty() == false)

现在:

复制代码
q = [9,20]

队列不为空,所以继续。

重新创建:

复制代码
vector<int> layer;

所以:

复制代码
layer = []

然后:

复制代码
int n = q.size();

现在:

复制代码
n = 2

代表:

当前第二层有两个节点:9 和 20。

开始内层循环。

先处理 9:

复制代码
TreeNode* node = q.front();

得到:

复制代码
node = 9

加入:

复制代码
layer = [9]

弹出:

复制代码
q = [20]

然后:

复制代码
n = 1

9 没有左右孩子,所以没有新节点入队。


接着因为:

复制代码
n = 1

继续内层循环。

现在:

复制代码
node = q.front();

得到:

复制代码
node = 20

加入:

复制代码
layer = [9,20]

弹出:

复制代码
q = []

然后:

复制代码
n = 0

但是 20 有两个孩子:

复制代码
15
7

所以:

复制代码
q = [15,7]

内层循环结束,因为:

复制代码
n = 0

然后:

复制代码
ans.push_back(layer);

得到:

复制代码
ans = [
    [3],
    [9,20]
]

第三层

现在:

复制代码
q = [15,7]

进入下一轮。

复制代码
int n = q.size();

所以:

复制代码
n = 2

处理 15:

复制代码
layer = [15]
q = [7]
n = 1

处理 7:

复制代码
layer = [15,7]
q = []
n = 0

两个节点都没有孩子。

所以:

复制代码
ans = [
    [3],
    [9,20],
    [15,7]
]

此时:

复制代码
q = []

所以外层:

复制代码
while(q.empty() == false)

不成立,整个遍历结束。


你可以把整个执行过程压缩成这样:

复制代码
开始:
q = [3]

第一层:
n = 1
处理 3
q = [9,20]

ans = [[3]]

----------------

第二层:
n = 2
处理 9
处理 20
q = [15,7]

ans = [[3], [9,20]]

----------------

第三层:
n = 2
处理 15
处理 7
q = []

ans = [[3], [9,20], [15,7]]

这段代码最核心其实就是这四个变量:

复制代码
queue<TreeNode*> q;

表示:

等待处理的节点。

复制代码
int n = q.size();

表示:

当前这一层有几个节点。

复制代码
vector<int> layer;

表示:

当前这一层的答案。

复制代码
vector<vector<int>> ans;

表示:

所有层的最终答案。

你尤其要理解:

复制代码
int n = q.size();

为什么必须提前保存。

因为处理当前层的时候,会不断执行:

复制代码
q.push(node->left);
q.push(node->right);

把下一层的节点加入队列。

例如第二层刚开始:

复制代码
q = [9,20]
n = 2

处理 20 后:

复制代码
q = [15,7]

但是我们不能继续处理 15、7,因为它们已经是第三层了。

所以使用:

复制代码
n

把当前层节点数量固定下来。

一句话记忆这道题:

外层 while 控制一层一层地走,内层 while 控制把当前这一层的所有节点处理完;处理当前节点时,把它的左右孩子加入队列,留给下一层处理。

相关推荐
lzhdim14 小时前
AI的分类
人工智能·算法·机器学习·分类·数据挖掘
凤凰院凶涛QAQ17 小时前
《Java版数据结构 & 集合类剖析》Map & Set & 反射:“从哈希碰撞到红黑树转换,反射帮你扒开 HashMap 的桶数组看个究竟”
java·数据结构·算法
w_zero_one19 小时前
算法--模拟
java·数据结构·算法
秋天的怀念_David20 小时前
算法一千零一夜 · 第十三夜 幻方,武侠世界里的数学迷宫
java·程序人生·算法
lll235269177920 小时前
HR如何快速整理面试沟通内容?
面试·职场和发展
零售校长20 小时前
西湖区零售门店店长面试怎么准备
面试·职场和发展·零售
秋天的怀念_David20 小时前
算法一千零一夜 · 第十四夜 幻方与奇妙的二进制
java·程序人生·算法
薛定e的猫咪20 小时前
(ICLR 2020)MAML 靠的不是快速学习,而是特征复用
人工智能·深度学习·学习·算法·机器学习
薛定e的猫咪21 小时前
(ICLR 2026)DF-META:面向 FJSP 的无导数元学习实例自适应调度
人工智能·深度学习·学习·算法·机器学习
java_nnnn1 天前
LeetCode刷题滑动窗口(水果成篮+找到字符串中所有字母的异位词)Java
java·开发语言·leetcode