序: 题目概览

![[附件/Pasted image 20250802203312.png||700]]

0、理论基础

0.1 二叉树的高度和深度

(对某个节点来说)
深度是指从根节点到该节点的最长简单路径边的条数;
高度是指从最下面的叶子节点到该节点的最长简单路径边的条数;
(对二叉树)
深度是从根节点数到它的叶节点;
高度是从叶节点数到它的根节点;
注意: 树的深度和高度一样,但是具体到树的某个节点,其深度和高度不一样。
![[附件/Pasted image 20250802212942.png]]

如图:树的高度和深度都为4(看层数);
节点8的深度为3;节点9的高度为2;

0.2 二叉树的种类

0.2.1 满二叉树

如果一颗二叉树只有度为0的节点和度为2的节点,并且度为0的节点在同一层中,则这颗二叉树成为满二叉树。

![[附件/Pasted image 20250802214351.png||400]]
也可以成为深度为k,则总节点数为2^k - 1

0.2.2 完全二叉树

除了最底层节点没有填完,其余每层节点都达到最大值,并且最下面一层的节点都集中在该层最左侧位置。
若最底层为第h层,则该层包含1~2^(h-1)个节点。
![[附件/Pasted image 20250802214628.png||600]]

0.2.3 二叉搜索数

二叉搜索树有数值,二叉搜索树是一个有序数。
左子树节点值都小于根节点值。
右子树节点值都大于根节点值。

![[附件/Pasted image 20250802214921.png||600]]

0.2.4 平衡二叉搜索树

平衡二叉搜索数,又被称为AVL(Adelson-Velsky and Landis),要么是一颗空树,要么左右两子树高度绝对值不超过1。
![[附件/Pasted image 20250802215215.png||600]]

C++中map、set、multimap,multiset的底层实现都是平衡二叉搜索树,所以map、set的增删操作时间时间复杂度是logn。

0.3 二叉树的存储方式

分为链式存储顺序存储两种方式,前者使用指针实现,后者使用数组实现。

链式存储,示意图如下:
![[附件/Pasted image 20250802215705.png||700]]

顺序存储(使用数组),如下图所示。
![[附件/Pasted image 20250802215814.png||700]]
如果父节点的数组下标是 i,那么它的左孩子就是 i 2 + 1,右孩子就是 i 2 + 2。

但是用链式表示的二叉树,更有利于我们理解,所以一般我们都是用链式存储二叉树。

0.4 二叉树的遍历方式

主要有深度优先遍历广度优先遍历

深度优先遍历:先往深走,遇到叶子节点再往回走。(递归法实现、迭代法实现)
广度优先遍历:一层一层遍历。(迭代法实现)

深度优先遍历的拓展:(要点:前中后指的是中间节点的位置即可。)

  • 前序遍历:中左右
  • 中序遍历:中左右
  • 后续遍历:左右中
    例如:
    ![[附件/Pasted image 20250802220426.png||700]]

0.5 二叉树的定义

C++ 代码如下

struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

1 二叉树的递归遍历(力扣:144、145、94)

1.1 递归原理及具体实现

  • 确定递归函数的参数和返回值;确定哪些参数是需要处理的,然后就在递归函数里加上这个参数,并且还要明确每次递归的返回值及返回类型。
  • 确定终止条件:终止条件务必要清楚。
  • 确定单层递归逻辑:即每一层递归要处理的数据,也就是会重复调用自己来实现递归的过程。
    以前序遍历举例:

    class Solution {
    public:
      void traversal(TreeNode* cur, vector<int>& vec) {
          if (cur == NULL) return;
          vec.push_back(cur->val);    // 中
          traversal(cur->left, vec);  // 左
          traversal(cur->right, vec); // 右
      }
      vector<int> preorderTraversal(TreeNode* root) {
          vector<int> result;
          traversal(root, result);
          return result;
      }
    };
    

1.2 力扣144:前序遍历

1.2.1 题目描述

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

示例 1:

输入:root = [1,null,2,3]

输出:[1,2,3]

解释:

||200

示例 2:

输入:root = [1,2,3,4,5,null,8,null,null,6,7,9]

输出:[1,2,4,5,6,7,3,8,9]

解释:

||400

示例 3:

输入:root = []

输出:[]

示例 4:

输入:root = [1]

输出:[1]

1.2.2 题目解析

(解析 = nullptr)

1.2.3 具体代码

/**

 * 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(TreeNode* cur, vector<int>& result){
        if(cur == nullptr) return;  //终止条件
        result.push_back(cur->val);  //具体实现
        traversal(cur->left, result);
        traversal(cur->right, result);
    }

    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result; //定义结果数组
        traversal(root, result);
        return result;
    }
};

1.3 力扣145:后续遍历

1.3.1 题目描述

给你一棵二叉树的根节点 root ,返回其节点值的 后序遍历 。

示例 1:

输入:root = [1,null,2,3]

输出:[3,2,1]

解释:

||200

1.3.2 题目解析

(解析 = nullptr)

1.3.3 具体代码

/**
 * 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(TreeNode* cur, vector<int> &result){
        if(cur == nullptr) return;
        traversal(cur->left, result);
        traversal(cur->right, result);
        result.push_back(cur->val);
    }

    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        traversal(root, result);
        return result;
    }
};

1.4 力扣94:中序遍历

1.4.1 题目描述

给定数组,中序遍历

1.4.2 题目解析

nullptr

1.4.3 具体代码

/**
 * 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(TreeNode* cur, vector<int> &result){
        if(cur == nullptr) return;
        traversal(cur->left, result);
        result.push_back(cur->val);
        traversal(cur->right, result);
    }

  
    vector<int> inorderTraversal(TreeNode* root) {
    vector<int> result;
    traversal(root, result);
    return result;    
    }

};

2 二叉树的层序遍历

对应力扣102、107、199、637、429、515、116、117、104、111这10道题目。

2.1 代码模板

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        queue<TreeNode*> que;               //构建一个储存TreeNode指针的队列
        if (root != NULL) que.push(root);   //如果根节点不为空,则将其加入队列
        vector<vector<int>> result;         //构建用于存储最终结果的二维数组

        //遍历队列核心代码
        //主要队列不为空,就继续处理
        while (!que.empty()) {    
            int size = que.size();                         //记录当前层的大小,便于后续处理,这里的数据是后面执行过程中添加进去的。
            vector<int> vec;                               //用于储存当前层的节点值

            //遍历当前层的所有节点
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();              //获取队首节点
                que.pop();                                 //弹出队首节点
                vec.push_back(node->val);                  //将当前节点的值加入当前层的数组
                if (node->left) que.push(node->left);      //将当前节点的子节点加入队列(为下一层做遍历)
                if (node->right) que.push(node->right);
            }
            result.push_back(vec);                         //将当前层的结果加入最终结果
        }
        return result;                                     //返回层序遍历的结果
    }
};