前言
二叉树递归遍历和二叉树迭代遍历 实现的前中后序遍历都归类深度搜索;
广度搜索如何实现?一层结束,再继续下一层搜索:层序遍历。
一、题目阅读
【102.二叉树的层序遍历】
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
示例 2:
输入:root = [1]
输出:[[1]]
示例 3:
输入:root = []
输出:[]
提示:
树中节点数目在范围 [0, 2000] 内
-1000 <= Node.val <= 1000
二、尝试实现
思路
(1)深度搜索中迭代循环使用的数据结构是栈,也是递归实现的原理。那么广度搜索(层序遍历)可不可以有数据结构用呢?如果还用栈,放入左右孩子时,无论是先入谁,出栈都不是按层出。所以得换。
(2)用队列怎么样?先把根节点入队,再入左孩子,再入右孩子。出队时,排序是层序结构。选定队列结构。
(3)如果只是输出顺序,用队列把左右孩子不为空时,放入队列,按顺序出队就好了;但是结果需要按层划分数组,这就麻烦点。
(4)如果按sum求和,到第二层时sum=3,……到第n层是sum = 2^n -1。如果少了一边孩子,无法计数,依靠数量关系不好处理。
(5)受迭代统一写法启发,如果每一层结束后面紧跟着null标记,从队列中取出空节点,说明一层结束,这就有了标志,nice。
代码实现
用迭代实现:
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> result; //先把返回值搞好queue<TreeNode*> que; //定义一个队列if(root == nullptr) return result;que.push(root); //如果第一层不是空,放入队列que.push(nullptr);//紧接着放入null,表示第一层结束。vector<int> levelrecord;//每一层的数组while(!que.empty()){TreeNode* cur = que.front();//获取队列出口元素if(cur!=nullptr){ //如果不为空,把左右孩子放入队列,前提左右孩子不为空时。if(cur->left) que.push(cur->left);if(cur->right) que.push(cur->right);que.pop(); //取出出口元素levelrecord.push_back(cur->val);//放入当前层的数组中}else{ //如果取到空,说明这一层数组填好了。该往result里面放。que.pop(); //弹出空指针if(!levelrecord.empty()) result.push_back(levelrecord); //如果该层不为空放入resultif(que.back() != nullptr){ //当队列还有元素,把层标记放进去;如果没有元素,说明已经到最后一层了,不用放入。que.push(nullptr);}levelrecord.clear(); //新的一层开始,清空上一层的存放}}return result;}
};
三、参考思路
二叉树层序遍历参考链接
学习内容
(1)借助队列,保存每一层的数据。如何实现?
(2)当一层的数组要放入result中时,用size来记录当前队列里元素的数量,这个数量是下一层的个数。只pop出size个元素放到当前层数组中。
(3)这样就不会出现两层元素混在一起。不知道这一层应该有几个元素。
对比思路总结:都是用队列来记录每一层的元素,但是如何知道每层元素个数方式不太一样:
- 参考给出用size记录;
- 个人想借助null标记表示一层结束。
代码实现
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> result;queue<TreeNode*> que;if(root != nullptr) que.push(root);while(!que.empty()){int size = que.size(); //在还没遍历这一层时,先把这一层的元素个数记录下来。vector<int> levelrecord;while(size--){ //边遍历边放入下一层元素。TreeNode* top = que.front();que.pop();if(top->left) que.push(top->left);if(top->right) que.push(top->right);levelrecord.push_back(top->val);}result.push_back(levelrecord);}return result;}
};
总结
本文记录二叉树层序遍历(广度搜索)的实现。
- 借助队列结构;
- 在遍历之前,记录每一层的个数。避免两层元素混在一起。
补充
迭代法:直接用循环实现同一段代码的重复操作;
递归:通过自己调用自己,也实现某段代码的重复操作。
那么用递归来实现层序遍历呢?
递归思路
- 每一层遍历都是重复的操作,所以把层遍历的while(size- -)改成函数,实现递归。获得一层的数组。
- 在主函数的while中调用递归函数。
代码实现
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:void traversal(queue<TreeNode*>& q,vector<int>& levelrecord,int size){if(size == 0){ //确定回归的终止条件return;}//还不到回归的条件TreeNode* cur = q.front();q.pop();if(cur->left) q.push(cur->left);if(cur->right) q.push(cur->right);levelrecord.push_back(cur->val);size--;traversal(q,levelrecord,size); //重复执行}vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> result;queue<TreeNode*> que;if(root != nullptr) que.push(root);while(!que.empty()){int size =que.size();vector<int> vec;traversal(que,vec,size);result.push_back(vec);}return result;}
};
对比参考代码:
(1)在主函数中只调用一次递归函数,函数返回后,就可以return result。
(2)在递归函数order中:
- 多层同时开展,先处理自己;再order左孩子;再order右孩子。
- 如果没有新开一层,result已经放了该层数组
- 如果新开一层,result需要push_back新数组。
流程如下:
/*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}* };*/
class Solution {
public:void order(TreeNode* cur,vector<vector<int>>& result,int depth){if(cur == nullptr) return; //终止条件if(result.size() == depth ) result.push_back(vector<int> ());//新开一层,放入新数组,空的。result[depth].push_back(cur->val);order(cur->left,result,depth+1);//左孩子在下一层,所以result的下标应该+1order(cur->right,result,depth+1);//先左孩子再右孩子,可以使那一层从左到右。}vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> result;int depth = 0;//因为result数组下标从0开始order(root,result,depth);return result;}
};
(欢迎指正,转载标明出处)