题目:递归遍历,迭代遍历,统一遍历,层序遍历
需要重做:递归,迭代,层序的模板和他的 116.填充每个节点的下一个右侧节点指针
理论基础
见代码随想录的二叉树1
遍历:深度优先:前中后序遍历(指中间节点是先还是中还是后) ---递归,栈
广度优先--队列
递归遍历 (必须掌握)
递归三要素:
-
确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
-
确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
-
确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
1.前序遍历:
class Solution {
public:
void traversal(TreeNode* cur,vector<int>&res){
if(cur==nullptr)return;
res.push_back(cur->val);
traversal(cur->left,res);
traversal(cur->right,res);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int>res;
traversal(root,res);
return res;
}
};
2.后序遍历
class Solution {
public:
void traversal(TreeNode*cur,vector<int>&res){
if(cur==nullptr)return;
traversal(cur->left,res);
traversal(cur->right,res);
res.push_back(cur->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int>res;
traversal(root,res);
return res;
}
};
3.中序遍历
class Solution {
public:
void traversal(TreeNode*cur,vector<int>&res){
if(cur==nullptr)return;
traversal(cur->left,res);
res.push_back(cur->val);
traversal(cur->right,res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int>res;
traversal(root,res);
return res;
}
};
迭代遍历 (基础不好的录友,迭代法可以放过)
即非递归方式的深度遍历。
1.前序:
思路:
使用栈来进行。前序:中左右。
如果树为空,直接返回。如果不为空,则进行遍历。
当栈不为空的时候,弹出栈顶,记录数值,然后分别按右左顺序进栈,这样出来就是左右。
代码:
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int>res;
stack<TreeNode*>st;
//如果为空,则直接返回
if(root==nullptr)return res;
st.push(root);
//当栈不为空,循环
while(!st.empty()){
//首先让栈顶出栈,然后按照右左的顺序入栈(这样出来才是左右的顺序)
TreeNode*cur=st.top();
st.pop();
res.push_back(cur->val);
if(cur->right!=nullptr)st.push(cur->right);
if(cur->left!=nullptr)st.push(cur->left);
}
return res;
}
};
2.中序:
思路:
左中右的顺序进行遍历。进栈的是cur!!!否则下面需要分很多情况。
cur就是当前指向的,如果cur!=nullptr,那么cur进栈,cur=cur->left。否则cur=st.top,然后st pop,res记录值,然后cur=cur->right
代码:
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int>res;
stack<TreeNode*>st;
if(root==nullptr)return res;
TreeNode*cur=root;
while(cur!=nullptr||!st.empty()){
if(cur!=nullptr){
st.push(cur);
cur=cur->left;
}
else{
cur=st.top();
st.pop();
res.push_back(cur->val);
cur=cur->right;
}
}
return res;
}
};
3.后序:
思路:
顺序应为左右中
前序遍历:中左右-》左右交换:中右左-》整体反转-》左右中;
所以只需要在前序的基础上交换右左,最后得到的再整体反转即可
代码:
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int>res;
stack<TreeNode*>st;
if(root==nullptr)return res;
TreeNode*cur=root;
st.push(cur);
while(!st.empty()){
cur=st.top();
st.pop();
res.push_back(cur->val);
if(cur->left!=nullptr)st.push(cur->left);
if(cur->right!=nullptr)st.push(cur->right);
}
reverse(res.begin(),res.end());
return res;
}
};
统一迭代 (基础不好的录友,迭代法可以放过)
不掌握了,选择掌握不统一的写法
层序遍历
1.非递归:
思路:
使用队列,当队列不为空,pop队列,对这个的值记录,然后如果他左右子树不为空,就把左右分别加到队尾。(使用while,并使用size来判断本层有几个元素要pop)
代码:
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
queue<TreeNode*>q;
vector<vector<int>>res;
if(root!=nullptr)q.push(root);
while(!q.empty()){
int size=q.size();
vector<int>ress;
for(int i=0;i<size;i++){
TreeNode*tmp=q.front();
ress.push_back(tmp->val);
q.pop();
if(tmp->left)q.push(tmp->left);
if(tmp->right)q.push(tmp->right);
}
res.push_back(ress);
}
return res;
}
};
2.递归:
思路:记录深度,深度一样的放在一个数组里面
void order(vector<vector<int>>res, int depth, treeNode* cur)
停止条件:为空
里面要干什么:如果是这层的开始,则要加上一个空vector,然后在res【depth】里push_back.然后左边递归,右边递归。
注意这里的递归不需要判断是否为空,因为在递归开始有截断!!
注意:一定注意需要vector的引用!!!!因为要改变里面的值!!
代码:
class Solution {
public:
void order(vector<vector<int>>&res,int depth,TreeNode*cur){
if(cur==nullptr)return;
//下面这一句的作用是,当遍历到新的一层时,先开一个vector放到res中
if(res.size()==depth)res.push_back(vector<int>());
res[depth].push_back(cur->val);
order(res,depth+1,cur->left);
order(res,depth+1,cur->right);
}
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>>res;
int depth=0;
order(res,depth,root);
return res;
}
};
例题:9道:
思路:就是上面的两个例子
代码:同上
思路:在广度优先的基础上,最后reverse一下就行
代码:
class Solution {
public:
vector<vector<int>> levelOrderBottom(TreeNode* root) {
queue<TreeNode*>q;
vector<vector<int>>res;
if(root!=nullptr)q.push(root);
while(!q.empty()){
int size=q.size();
vector<int>ress;
for(int i=0;i<size;i++){
TreeNode*tmp=q.front();
ress.push_back(tmp->val);
q.pop();
if(tmp->left)q.push(tmp->left);
if(tmp->right)q.push(tmp->right);
}
res.push_back(ress);
}
reverse(res.begin(),res.end());
return res;
}
};
思路:层序遍历,加只用统计i==size-1的时候的值
代码:
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
queue<TreeNode*>q;
vector<int>res;
if(root!=nullptr)q.push(root);
while(!q.empty()){
int size=q.size();
for(int i=0;i<size;i++){
TreeNode*tmp=q.front();
if(i==size-1)res.push_back(tmp->val);
q.pop();
if(tmp->left)q.push(tmp->left);
if(tmp->right)q.push(tmp->right);
}
}
return res;
}
};
思路:加一个sum统计每层的总和,最后返回平均
代码:
class Solution {
public:
vector<double> averageOfLevels(TreeNode* root) {
vector<double>res;
queue<TreeNode*>q;
if(root!=nullptr)q.push(root);
while(!q.empty()){
double sum=0;
int size=q.size();
for(int i=0;i<size;i++){
TreeNode*tmp=q.front();
sum+=tmp->val;
q.pop();
if(tmp->left)q.push(tmp->left);
if(tmp->right)q.push(tmp->right);
}
res.push_back(sum/size);
}
return res;
}
};
思路:把加入子节点的地方修改一下即可
代码:
class Solution {
public:
vector<vector<int>> levelOrder(Node* root) {
queue<Node*>q;
vector<vector<int>>res;
if(root!=nullptr)q.push(root);
while(!q.empty()){
int size=q.size();
vector<int>ress;
for(int i=0;i<size;i++){
Node*tmp=q.front();
ress.push_back(tmp->val);
q.pop();
for(int i =0;i<tmp->children.size();i++){
q.push(tmp->children[i]);
}
}
res.push_back(ress);
}
return res;
}
};
思路:每行加个max即可
代码:
class Solution {
public:
vector<int> largestValues(TreeNode* root) {
queue<TreeNode*>q;
vector<int>res;
if(root!=nullptr)q.push(root);
while(!q.empty()){
int size=q.size();
int max=q.front()->val;
for(int i=0;i<size;i++){
TreeNode*tmp=q.front();
if(tmp->val>max)max=tmp->val;
q.pop();
if(tmp->left)q.push(tmp->left);
if(tmp->right)q.push(tmp->right);
}
res.push_back(max);
}
return res;
}
};
思路:这题有难度,需要定义一个pre,来保留pre-》next=tmp
代码:
class Solution {
public:
Node* connect(Node* root) {
queue<Node*>q;
if(root!=nullptr)q.push(root);
while(!q.empty()){
int size=q.size();
Node* pre;
Node* tmp;
for(int i=0;i<size;i++){
if(i==0){
pre=q.front();
tmp=q.front();
q.pop();
}
else{
tmp=q.front();
q.pop();
pre->next=tmp;
pre=tmp;
}
if(tmp->left)q.push(tmp->left);
if(tmp->right)q.push(tmp->right);
}
pre->next=nullptr;
}
return root;
}
};
思路:同上,一摸一样的代码
代码:
思路:套模板即可,每遍历一层就++
代码:
class Solution {
public:
int maxDepth(TreeNode* root) {
queue<TreeNode*>q;
int depth=0;
if(root!=nullptr)q.push(root);
while(!q.empty()){
int size=q.size();
for(int i=0;i<size;i++){
TreeNode*tmp=q.front();
q.pop();
if(tmp->left)q.push(tmp->left);
if(tmp->right)q.push(tmp->right);
}
depth++;
}
return depth;
}
};
思路:套模板,如果左右孩子都为空,则返回depth+1
代码:
class Solution {
public:
int minDepth(TreeNode* root) {
queue<TreeNode*>q;
int depth=0;
if(root!=nullptr)q.push(root);
while(!q.empty()){
int size=q.size();
for(int i=0;i<size;i++){
TreeNode*tmp=q.front();
q.pop();
if(!tmp->left&&!tmp->right)return depth+1;
if(tmp->left)q.push(tmp->left);
if(tmp->right)q.push(tmp->right);
}
depth++;
}
return depth;
}
};
总结:
复习并掌握深搜和广搜了。
做吐题的一天)