专题:二叉树递归遍历

1.二叉树的前序遍历 后序遍历 中序遍历 以及非递归写法

递归写法:

前序遍历

cpp 复制代码
class Solution {
    vector<int> res{};
    void dfs(TreeNode* root) {
      if(root==nullptr) return;
      res.push_back(root->val);
      dfs(root->left);
      dfs(root->right);
      return;
    }
    
public:
    vector<int> postorderTraversal(TreeNode* root) {
      dfs(root);
      return res;
    }
};

后序遍历

cpp 复制代码
class Solution {
    vector<int> res{};
    void dfs(TreeNode* root) {
      if(root==nullptr) return;
      dfs(root->left);
      dfs(root->right);
      res.push_back(root->val);
      return;
    }
    
public:
    vector<int> postorderTraversal(TreeNode* root) {
      dfs(root);
      return res;
    }
};

中序遍历

cpp 复制代码
class Solution {
    vector<int> res{};
    void dfs(TreeNode* root) {
      if(root==nullptr) return;
      dfs(root->left);
      res.push_back(root->val);
      dfs(root->right);
      return;
    }
    
public:
    vector<int> postorderTraversal(TreeNode* root) {
      dfs(root);
      return res;
    }
};

非递归写法:

前序遍历

cpp 复制代码
class Solution {


public:
    vector<int> preorderTraversal(TreeNode* root) {
      // 非递归写法 根左右
      vector<int> res{};
      stack<TreeNode*> s;
      if(root == nullptr) return {};
      s.push(root);
      while(!s.empty()){
        auto node = s.top();
        s.pop();
        
        res.push_back(node->val);
        if(node->right){
          s.push(node->right);
        }
        if(node->left){
          s.push(node->left);
        }
        // cout<<"{";
        // for(auto val :s){
        //   cout<<","<<val<<endl;
        // }
        // cout<<"}"<<endl;
      }
      return res;
    }
};

后续遍历 非递归写法就是 根右左 最后reverse就是 左右根了 注意和前序遍历非递归写法入栈顺序不同 前序非递归写法后入左孩子 后续需后入右孩子

cpp 复制代码
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
      // 非递归写法 根左右
      vector<int> res{};
      stack<TreeNode*> s;
      if(root == nullptr) return {};
      s.push(root);
      while(!s.empty()){
        auto node = s.top();
        s.pop();
        
        res.push_back(node->val);
        if(node->left){
          s.push(node->left);
        }
        if(node->right){
          s.push(node->right);
        }
        // cout<<"{";
        // for(auto val :s){
        //   cout<<","<<val<<endl;
        // }
        // cout<<"}"<<endl;
      }
      reverse(res.begin(),res.end());
      return res;
    }
};

中序遍历 注意这里非递归写法的前序和后序最大的不同是 入栈第一个元素 并是不取出来的第一个元素

cpp 复制代码
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> res{};
      // 非递归写法 左根右
      stack<TreeNode*> s;
      auto cur = root;
      if(cur==nullptr){
        return {};
      }
      while(!s.empty()||cur!=nullptr){
        while(cur){
            s.push(cur);
            cur=cur->left;
        }
        TreeNode * pnode = s.top();
        s.pop();
        res.push_back(pnode->val);
        // cout<<"pnode->val:"<<pnode->val<<"   s.size():"<<s.size()<<endl;
        if(pnode->right){
           cur = pnode->right;
        }
      }
      return res;
    }
};

ps:递归写法后续遍历不使用全局变量写法

```cpp
class Solution {
    vector<int> res{};
    void dfs(TreeNode* root) {
      if(root==nullptr) return;
      dfs(root->left);
      dfs(root->right);
      res.push_back(root->val);
      return;
    }
    
public:
    vector<int> postorderTraversal(TreeNode* root) {
      if(root==nullptr) return{};
      vector<int> le = postorderTraversal(root->left);
      vector<int> ri = postorderTraversal(root->right);

      vector<int> cur{};
      if(!le.empty()){
         cur.insert(cur.begin(), le.begin(),le.end());
      }
      if(!ri.empty()){
         cur.insert(cur.end(), ri.begin(),ri.end());
      }
      cur.push_back(root->val);
      // cout<<"le.size:"<<le.size()<<"    ri.size:"<<ri.size()<<endl;
      // cout<<"root:val:"<<root->val<<endl<<endl;
      return cur; 
    }
};
**2.[二叉树层序遍历](https://leetcode.cn/problems/binary-tree-level-order-traversal/description/)**

```cpp
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        // 要用队列
        deque<TreeNode*> qu;
        vector<vector<int>> res_vv{};
        if(root==nullptr){
           return res_vv;
        }
        qu.push_back(root);
        while(!qu.empty()){
          int size = qu.size();
          vector<int> res{};
          for(int i=0;i<size;i++){
            auto pnode = qu.front();
            qu.pop_front();
            res.push_back(pnode->val);

            // 该节点是否存在左右节点
            if(pnode->left){
              qu.push_back(pnode->left);
            }
            if(pnode->right){
              qu.push_back(pnode->right);
            }
          }
          res_vv.push_back(res);
        }
        return res_vv;
    }
};

上面代码需要注意的是 int size = qu.size(); 每层遍历的时候需要重新取一次 for(int i=0;i<qu.size();i++) 因为循环体内队列里面添加元素 qu.size()会实时变化的

3.翻转二叉树

cpp 复制代码
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        //   确定是否需要返回值(和题目的递归函数函数是否有返回值无关) 确定遍历顺序(有返回值接的需要接住) 确定结束条件(注意是否存在中途直接return)  确定单层循环逻辑
        if(root==nullptr) return nullptr;
        auto temp = root->left;
        root->left = root->right;
        root->right = temp;

        invertTree(root->left);
        invertTree(root->right);
        return root;
    }
};

4.对称二叉树

cpp 复制代码
class Solution {
public:
    bool dfs(TreeNode* leftroot, TreeNode* rightroot){
        //   确定是否需要返回值(和题目的递归函数函数是否有返回值无关) 确定遍历顺序(有返回值接的需要接住) 确定结束条件(注意是否存在中途直接return)  确定单层循环逻辑
      if(leftroot == nullptr && rightroot == nullptr) return true;
      if(leftroot != nullptr && rightroot == nullptr) return false;
      if(leftroot == nullptr && rightroot != nullptr) return false;
      //   if(leftroot != nullptr && rightroot != nullptr)
      if(leftroot->val != rightroot->val) return false;
      // 后续遍历
      return dfs(leftroot->left,rightroot->right) &&  dfs(leftroot->right,rightroot->left);
    } 
    bool isSymmetric(TreeNode* root) {
        // 自上而下 但是中途会有提前结束 
        if(root==nullptr) return true;
        return dfs(root->left,root->right);
    }
};

这里遍历顺序可以说是后续遍历 但是中途存在提前退出循环的可能 表面看起来是自顶向下(前序遍历)

5.二叉树的最大深度

cpp 复制代码
class Solution {
public:
    int maxDepth(TreeNode* root) {
        // 确定是否需要返回值(和题目的递归函数函数是否有返回值无关) 确定遍历顺序(有返回值接的需要接住) 确定结束条件(注意是否存在中途直接return)  确定单层循环逻辑
        if(root == nullptr) return 0;
        if(root->left ==nullptr && root->right ==nullptr) return 1;
        int leftlen = maxDepth(root->left);
        int rightlen = maxDepth(root->right);
        int rootlen = max(leftlen,rightlen)+1;
        return rootlen;
    }
};

6.二叉树的最小深度

方法一 直接遍历到空节点

cpp 复制代码
public:
    int minDepth(TreeNode* root) {
        // 确定是否需要返回值(和题目的递归函数函数是否有返回值无关) 确定遍历顺序(有返回值接的需要接住) 确定结束条件(注意是否存在中途直接return)  确定单层循环逻辑
        if(root ==nullptr) return 0;
        int leftmin = minDepth(root->left);
        int rightmin = minDepth(root->right);
        int curtmin = 0;
        if(leftmin == 0){
            curtmin = rightmin+1;
        }else if(rightmin == 0){
            curtmin = leftmin+1;
        }else {
            curtmin = min(leftmin, rightmin) +1;
        }
        return curtmin;
    }
};

明显需要后续遍历 每次取左右两个做小的深度 但是我们要注意一点 上面的遍历方式一定会遍历到某个节点的左孩子/右孩子节点是空 此时不能直接取最小值 需要做特殊处理

cpp 复制代码
        if(leftmin == 0){
            curtmin = rightmin+1;
        }else if(rightmin == 0){
            curtmin = leftmin+1;
        }else {
            curtmin = min(leftmin, rightmin) +1;
        }

方法二 不遍历空节点 (递归需要保证头结点不为空 因此需要在主函数中直接判断)

cpp 复制代码
class Solution {
    int posdfs(TreeNode* root) {
        // 确定是否需要返回值(和题目的递归函数函数是否有返回值无关) 确定遍历顺序(有返回值接的需要接住) 确定结束条件(注意是否存在中途直接return)  确定单层循环逻辑
        if(root->left==nullptr && root->right==nullptr) return 1;
        int  leftmin, rightmin;
        cout<<"start"<<endl;
        if(root->left != nullptr && root->right == nullptr){
            leftmin = minDepth(root->left);
            // cout<<"leftmin:"<<leftmin+1<<endl;
            return leftmin+1;
        }
        if(root->left == nullptr && root->right != nullptr){
            rightmin = minDepth(root->right);
            // cout<<"rightmin:"<<rightmin+1<<endl;
            return rightmin+1;
        }
        // 左右都有高度
        int rootlen;
        leftmin = minDepth(root->left);
        rightmin = minDepth(root->right);
        rootlen = min(leftmin, rightmin)+1;
        // cout<<"rootlen:"<<rootlen<<endl<<endl;
        return rootlen;
    }
public:
    int minDepth(TreeNode* root) {
      if(root==nullptr) return 0;
      return posdfs(root);
    }
};

7.完全二叉树的节点个数

我们先看看普通二叉树的节点数目写法 后序遍历

cpp 复制代码
class Solution {
public:
    int countNodes(TreeNode* root) {
        if(root==nullptr) return 0;
        int leftcount = countNodes(root->left);
        int rightcount = countNodes(root->right);
        int rootcount = leftcount+rightcount+1;
        return rootcount;
    }
};

完全二叉树写法(其实也就是 结束条件里面有中途rerurn逻辑场景)

cpp 复制代码
class Solution {
public:
    int countNodes(TreeNode* root) {

        // 题目说是完全二叉树
        // 确定是否需要返回值(和题目的递归函数函数是否有返回值无关) 确定遍历顺序(有返回值接的需要接住) 确定结束条件(注意是否存在中途直接return)  确定单层循环逻辑
        if (root == nullptr) return 0;
        int leftdep=1,rightdep=1;
        TreeNode* lpnode = root, *rpnode = root;
        while(lpnode->left!=nullptr){
            lpnode = lpnode->left;
            leftdep++;
        }
        while(rpnode->right!=nullptr){
            rpnode = rpnode->right;
            rightdep++;
        }
        if (leftdep == rightdep) {
            // 这个节点(包含当前节点)以下都是满二叉树
            int curcount = (2<<(leftdep-1)) -1;
            return curcount;
        }
        int leftcount = countNodes(root->left);
        int rightcount = countNodes(root->right);
        int curcount = leftcount + rightcount + 1;
        return curcount;
    }
};

8.平衡二叉树

9.二叉树的所有路径

10.左叶子之和

11.找树左下角的值

12.路径总和

13.从中序与后序遍历序列构造二叉树

14.最大二叉树

相关推荐
Aurora_th36 分钟前
树与图的深度优先遍历(dfs的图论中的应用)
c++·算法·深度优先·图论·dfs·树的直径
马剑威(威哥爱编程)2 小时前
除了递归算法,要如何优化实现文件搜索功能
java·开发语言·算法·递归算法·威哥爱编程·memoization
算法萌新——13 小时前
洛谷P2240——贪心算法
算法·贪心算法
重生之我要进大厂3 小时前
LeetCode 876
java·开发语言·数据结构·算法·leetcode
KBDYD10104 小时前
C语言--结构体变量和数组的定义、初始化、赋值
c语言·开发语言·数据结构·算法
Crossoads4 小时前
【数据结构】排序算法---桶排序
c语言·开发语言·数据结构·算法·排序算法
自身就是太阳4 小时前
2024蓝桥杯省B好题分析
算法·职场和发展·蓝桥杯
孙小二写代码5 小时前
[leetcode刷题]面试经典150题之1合并两个有序数组(简单)
算法·leetcode·面试
little redcap5 小时前
第十九次CCF计算机软件能力认证-1246(过64%的代码-个人题解)
算法