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控制把当前这一层的所有节点处理完;处理当前节点时,把它的左右孩子加入队列,留给下一层处理。