与前序、中序、后序遍历相反,层次遍历的迭代实现是比较简单的。因为是从上到下,从左到右进行遍历,所以可以利用队列先进先出的性质保存中间结果。首先还是判空,如果root为空直接return空向量;否则将root入队列,并且作为第一层的遍历结果存入res中。遍历由两层循环实现,外循环用于将本层的遍历结果curLevel存入res,内循环通过访问上一层的遍历结果(即队列的前端),将其子节点保存作为本层遍历结果,同时被访问过的上层节点出队列。(这个过程自己动手画一下就很清楚了~)外循环的终止条件是队列为空,含义是上一层遍历中没有加入任何新的子节点,已经是最后一层(叶子节点)了。内层循环的终止条件是遍历次数达到上次遍历结束后队列的长度,即上层节点个数。
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
if (root == NULL) return {};
vector<vector<int>> res;
queue<TreeNode*> q;
q.push(root);
TreeNode* curNode;
int size;
while (!q.empty()) {
size = q.size();
vector<int> curLevel;
//每次都是从上一层的遍历结果中取出节点进行遍历
for (int i = 0; i < size; i++) {
curNode = q.front();
q.pop();
curLevel.push_back(curNode->val);
if (curNode->left) q.push(curNode->left);
if (curNode->right) q.push(curNode->right);
}
res.push_back(curLevel);
}
return res;
}
};
为了清楚地表现出分析的过程,所以每一层都申请了一个临时变量curLevel,但是这个变量真的有必要存在吗?其实res就已经蕴含了这个变量,所以只需要一个int变量指明当前是哪一层就好了,修改代码如下:
// 优化后,执行用时有了显著提升
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
if (root == NULL) return {};
vector<vector<int>> res;
queue<TreeNode*> q;
q.push(root);
TreeNode* curNode;
int size;
int curLevel = 0;
while (!q.empty()) {
size = q.size();
res.push_back({});
for (int i = 0; i < size; i++) {
curNode = q.front();
q.pop();
res[curLevel].push_back(curNode->val);
if (curNode->left) q.push(curNode->left);
if (curNode->right) q.push(curNode->right);
}
curLevel++;
}
return res;
}
};
接下来看看递归的写法。首先可以明确的是与前序、中序、后序遍历所用的DFS不同,层次遍历用到的是BFS,因此只需写一个BFS函数,在levelOrder中进行调用即可。首先对BFS函数进行接口设计,root指针是必不可少;res也需要在递归的过程中进行更新,所以作为出参传入;而对照上面的迭代版本,这里面有一个很明显的变量 – 层次,因此还需要一个参数:curLevel。因为是递归,所以显而易见的会有对左右子节点分别调用BFS函数这一步,在这之前需要把当前节点的值存入结果变量,那么什么时候将当前层的结果存入res中呢?因为res的每一个元素是一个代表了当前层遍历结果的一维向量,所以res的大小就是当前层数,当传入的curLevel等于res大小时,表明开始了新一层的遍历,需要将cur放入res中。if (res.size() == curLevel) res.push_back({}); 和 res[curLevel].push_back(root->val); 大概是整个递归版本里最难想到的两处,但其实如果一开始能把迭代想清楚,尤其是优化部分,其实转成递归就是顺其自然的事了~
// 在想到优化迭代版本之前写的递归,没有意识到res中已经包含了cur以及curLevel的作用,所以写出了错误的代码
class Solution {
public:
// 递归
void bfs(TreeNode* root, int curLevel, vector<vector<int>>& res) {
if (!root) return;
// 当前层次节点放入res中
vector<int> cur;
cur.push_back(root->val);
if (res.size() == curLevel) res.push_back(cur);
if (root->left) bfs(root->left, curLevel + 1, res);
if (root->right) bfs(root->right, curLevel + 1, res);
}
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
int curLevel = 0;
bfs(root, curLevel, res);
return res;
}
};
最终递归代码如下:
class Solution {
public:
// 递归
void bfs(TreeNode* root, int curLevel, vector<vector<int>>& res) {
if (!root) return;
// 当前层次节点放入res中
if (res.size() == curLevel) res.push_back({});
res[curLevel].push_back(root->val);
if (root->left) bfs(root->left, curLevel + 1, res);
if (root->right) bfs(root->right, curLevel + 1, res);
}
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
int curLevel = 0;
bfs(root, curLevel, res);
return res;
}
};