我们知道树/图的深度优先搜索使用递归可以很简单的实现,但树的广度优先搜索是依赖于队列先见先出的特性来实现的,不方便使用递归实现。今天我们来看看树的层序遍历方法,掌握了这个方法,广度优先搜索的大部分题都可以轻松解决了。
1. 二叉树的层序遍历
先看这个最简单的层序遍历,只需要按广度优先的顺序一个一个地输出节点值就可以了
要点:
- 头结点入队
- 队列不为空时不断出队,出队节点值加入结果
- 将出队节点的左右子节点入队
- 重复以上直到队列为空
vector<int> levelOrder(TreeNode* root) {
vector<int> res;
if(!root) return res;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
auto node = que.front();
que.pop();
res.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
return res;
}
102. 二叉树的层序遍历
剑指 Offer 32 - II. 从上到下打印二叉树 II
这个是一个稍复杂点的层序遍历,遍历过程还跟上面一题一样,只是要求输出结果按层存储。这就要求在队列中标记每一层的边界
- 第一种解法是每一层入队完成后加入空节点做哨兵。
要点:
- 头结点入队后再入队一个空节点(因为第一层只有一个空节点)
- 出队时只要弹出的节点不是空节点说明没到层尾,继续遍历和入度左右子节点
- 如果出队弹出的节点是空节点并且该层节点不为空(最后一一个空节点出队会时该层节点数为空),说明到了层尾,此时将该层结果加入结果集并清空该层结果,继续入队空节点
- 队列空遍历结束
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(!root) return res;
queue<TreeNode*> que;
que.push(root);
que.push(nullptr);
vector<int> temp;
while(!que.empty()){
auto node = que.front();
que.pop();
if(node){
temp.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}else if(!temp.empty()){
res.push_back(temp);
temp.clear();
que.push(nullptr);
}
}
return res;
}
- 第二种解法 通过记录未出队元素数目标记一层遍历结束
要点:
- 头结点入队
- 循环遍历队列时先记录未遍历节点数目(这就是当前层节点数)
- 循环递减当前层节点数直到为0,该层节点出队、加入结果集、左右子节点入队
- 一层遍历完之后结果加入结果集,该层结果清空
- 队列为空时遍历结束
时间复杂度也是O(n), 因为少加入了一些哨兵节点所以性能和内存消耗比第一种方法更好。
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(!root) return res;
queue<TreeNode*> que;
que.push(root);
vector<int> temp;
while(!que.empty()){
auto size = que.size();
while(size--){
auto node = que.front();
que.pop();
temp.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
res.push_back(temp);
temp.clear();
}
return res;
}
下面就是层序遍历的各种变种了,套路都是一样的,只有局部有小的调整。
2. 二叉树自底向上层序遍历
107. 二叉树的层序遍历 II
和上题一样,只需要最后将结果集逆置一下就可以了
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> res;
if(root == nullptr)
return res;
queue<TreeNode*> que;
que.push(root);
vector<int> temp;
while(!que.empty()){
auto size = que.size();
while(size--){
auto node = que.front();
que.pop();
temp.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
res.push_back(temp);
temp.clear();
}
reverse(res.begin(), res.end());
return res;
}
3. 二叉树锯齿形层序遍历
103. 二叉树的锯齿形层序遍历
与普通层序遍历的差异仅在于增加标志一层正序输出一层逆序输出
vector<vector<int>> res;
if(!root) return res;
queue<TreeNode*> que;
que.push(root);
vector<int> temp;
bool change = false;
while(!que.empty()){
auto size = que.size();
while(size--){
auto node = que.front();
que.pop();
temp.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
if(change) reverse(temp.begin(), temp.end());
change = !change;
res.push_back(temp);
temp.clear();
}
return res;
}
4. 多叉树的层序遍历
429. N 叉树的层序遍历
与二叉树的层序遍历基本一致
vector<vector<int>> levelOrder(Node* root) {
vector<vector<int>> res;
if(!root) return res;
queue<Node*> que;
que.push(root);
vector<int> temp;
while(!que.empty()){
auto size = que.size();
while(size--){
auto node = que.front();
que.pop();
temp.push_back(node->val);
for(const auto c : node->children)
if(c) que.push(c);
}
res.push_back(temp);
temp.clear();
}
return res;
}
5. 二叉树的层平均值
vector<double> averageOfLevels(TreeNode* root) {
vector<double> res;
if(!root) return res;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
auto size = que.size();
auto index = size;
double value{};
while(index--){
auto node = que.front();
que.pop();
value += node->val;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
res.push_back(value/size);
}
return res;
}
6. 二叉树的层最大值
515. 在每个树行中找最大值
剑指 Offer II 044. 二叉树每层的最大值
vector<int> largestValues(TreeNode* root) {
vector<int> res;
if(!root) return res;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
auto size = que.size();
int value = que.front()->val;
while(size--){
auto node = que.front();
que.pop();
value = max(value, node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
res.push_back(value);
}
return res;
}
7. 二叉树最底层最左边的值
513. 找树左下角的值
剑指 Offer II 045. 二叉树最底层最左边的值
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> que;
que.push(root);
int value = root->val;
while(!que.empty()){
value = que.front()->val;
auto size = que.size();
while(size--){
auto node = que.front();
que.pop();
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return value;
}
8. 二叉树的右侧视图
199. 二叉树的右视图
剑指 Offer II 046. 二叉树的右侧视图
vector<int> rightSideView(TreeNode* root) {
vector<int> res;
if(!root) return res;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
auto size = que.size();
auto index = size;
int value{};
while(index--){
auto node = que.front();
que.pop();
value = node->val;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
res.push_back(value);
}
return res;
}
9. 二叉树中插入一层
TreeNode* addOneRow(TreeNode* root, int val, int depth) {
if(!root || depth < 1) return nullptr;
if(depth == 1){
auto head = new TreeNode(val, root, nullptr);
return head;
}
queue<TreeNode*> que;
que.push(root);
int depthIndex = 1;
while(!que.empty()){
auto size = que.size();
while(size--){
auto node = que.front();
que.pop();
if(depthIndex == depth-1){
node->left = new TreeNode(val, node->left, nullptr);
node->right = new TreeNode(val, nullptr, node->right);
}else{
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
depthIndex++;
}
return root;
}
10. 二叉树层内最大元素和
int maxLevelSum(TreeNode* root) {
queue<TreeNode*> que;
que.push(root);
int maxSum = root->val;
int level = 1;
int maxLevel = level;
while(!que.empty()){
auto size = que.size();
int value{};
while(size--){
auto node = que.front();
que.pop();
value += node->val;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
if(value > maxSum) {
maxSum = value;
maxLevel = level;
}
level++;
}
return maxLevel;
}
11. 二叉树层数最深叶子节点的和
int deepestLeavesSum(TreeNode* root) {
queue<TreeNode*> que;
que.push(root);
int levelValueSum{};
while(!que.empty()){
auto size = que.size();
levelValueSum = 0;
while(size--){
auto node = que.front();
que.pop();
levelValueSum += node->val;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
}
return levelValueSum;
}
12. 二叉树的最大宽度
要点:
- 使用了完全二叉树的节点索引
- 为了防止索引整数溢出,每层索引都从0开始
int widthOfBinaryTree(TreeNode* root) {
if(!root)
return 0;
queue<pair<TreeNode*,int>> que;
que.push({root, 1});
int maxWidth = 1;
while(!que.empty()){
auto size = que.size();
int start = que.front().second;
int end = 0;
while(size-- > 0){
auto nodeInfo = que.front();
que.pop();
auto& node = nodeInfo.first;
auto index = nodeInfo.second;
end = index;
if(node->left) que.push({node->left, 2*index-2*start});
if(node->right) que.push({node->right, 2*index+1-2*start});
}
maxWidth = max(maxWidth, end-start+1);
}
return maxWidth;
}