数据结构——二叉树

**二叉树(**Binary Tree) 是由n个结点构成的有限集(n≥0),n=0时为空树,n>0时为非空树。对于非空树:

  • 有且仅有一个根结点;
  • 除根结点外的其余结点又可分为两个不相交的子集 ,分别称为T 的左子树和右子树,且左子树和右子树本身又都是二叉树。

二叉树性质

  1. 任意二叉树第 i ii 层最大结点数为2^(i-1) (i>=1)
  2. 深度为 k kk 的二叉树最大结点总数为2^k − 1 。 ( k ≥ 1 )
  3. 对于任意二叉树,用n0,n1,n2分别表示叶子结点,度为1的结点,度为2的结点的个数,则有关系式n 0 = n 2 + 1
  4. n个结点完全二叉树深度为⌊log2n⌋ + 1

二叉树分类

二叉树主要分为四类:满二叉树、完全二叉树、二叉搜索树、平衡二叉搜索树

满二叉树

满二叉树就是除了叶子节点,其它节点都有左右子树,是一种特殊的完全二叉树

满二叉树有个优势 ,就是它的节点个数很好算。假设深度为 h,那么总节点数就是2^h - 1,等比数列求和。

完全二叉树

完全二叉树是指,除了最后一层,二叉树其他每层都必须是满的,且最下面一层的节点都集中在该层最左边的若干位置:

如下:

平衡二叉树

平衡二叉树定义为:一个二叉树每个节点 的左右两个子树的高度差的绝对值小于2。如下图:

二叉搜索树

前面介绍的树,都没有数值的,而二叉搜索树是有数值的了,二叉搜索树是一个有序树,也叫二叉排序树。

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
  • 它的左、右子树也分别为二叉排序树

平衡二叉搜索树

它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树:

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

二叉树存储方式

顺序存储

使用一组地址连续的存储单元存储,例如数组。为了在存储结构中能得到父子结点之间的映射关系,二叉树中的结点必须按层次遍历的顺序存放。具体是:

  • 对于完全二叉树,只需要自根结点起从上往下、从左往右依次存储。
  • 对于非完全二叉树,首先将它变换为完全二叉树,空缺位置用某个特殊字符代替(比如#),然后仍按完全二叉树的存储方式存储。

如果父节点的数组下标是 i,那么它的左孩子就是 i * 2 + 1,右孩子就是 i * 2 + 2。

链式存储

对每个结点,除数据域外再多增加左右两个指针域,分别指向该结点的左孩子和右孩子结点,再用一个头指针指向根结点。对应的存储结构:

相关题目

94. 二叉树的中序遍历 - 力扣(LeetCode)

104. 二叉树的最大深度 - 力扣(LeetCode)

226. 翻转二叉树 - 力扣(LeetCode)

101. 对称二叉树 - 力扣(LeetCode)

543. 二叉树的直径 - 力扣(LeetCode)

102. 二叉树的层序遍历 - 力扣(LeetCode)

108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)

98. 验证二叉搜索树 - 力扣(LeetCode)

230. 二叉搜索树中第 K 小的元素 - 力扣(LeetCode)

114. 二叉树展开为链表 - 力扣(LeetCode)

105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)

236. 二叉树的最近公共祖先 - 力扣(LeetCode)

124. 二叉树中的最大路径和 - 力扣(LeetCode)

437. 路径总和 III - 力扣(LeetCode)

二叉树的中序遍历

给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。

递归解法:

cpp 复制代码
/**
 * 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<int> ans;
    vector<int> inorderTraversal(TreeNode* root) {
        //1.递归---左根右
        if(!root) return {};
        inorderTraversal(root->left);
        ans.push_back(root->val);
        inorderTraversal(root->right);  
        return ans;
  }
}

迭代解法

cpp 复制代码
/**
 * 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<int> ans;
    vector<int> inorderTraversal(TreeNode* root) {
           //迭代---栈
        stack<TreeNode*> st;
        TreeNode* cur = root;
        while(cur || !st.empty()) {
            while(cur){
                st.push(cur);
                cur = cur->left;
            }
            cur = st.top();
            st.pop();
            ans.push_back(cur->val);
            cur = cur->right;
        }
    return ans;
    }
};

二叉树的最大深度

给定一个二叉树 root ,返回其最大深度。

二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。

cpp 复制代码
/**
 * 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:
    int maxDepth(TreeNode* root) {
        // if(!root) return 0;
        // int l = maxDepth(root->left);
        // int r = maxDepth(root->right);
        // return 1 + max(l,r);
        if(!root) return 0;
        TreeNode* cur = root;
        queue<TreeNode*> q;
        int ans = 0;
        q.push(root);
        while(!q.empty()){
            ans++;
            int n = q.size();
            for(int i = 0;i < n;i++){
                cur = q.front();
                q.pop();
                if(cur->left) q.push(cur->left);
                if(cur->right) q.push(cur->right);
            }
        }
        return ans;
    }
};

翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

cpp 复制代码
/**
 * 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:
    TreeNode* invertTree(TreeNode* root) {
        if(!root) return nullptr;
        //先序
        // TreeNode* t = root->left;
        // root->left = root->right;
        // root->right = t;
        // invertTree(root->left);
        // invertTree(root->right);
        // return root;

        //后序
        TreeNode* left = invertTree(root->left);
        TreeNode* right = invertTree(root->right);
        root->left = right;
        root->right = left;
        return root;
    }
};

对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。

cpp 复制代码
/**
 * 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:
    bool isSymmetric(TreeNode* root) {
        if(!root) return true;
        return dfs(root->left,root->right);
    }

    bool dfs(TreeNode* l,TreeNode* r){
        if( !l && !r) return true;
        else if((l && !r) || (!l && r) || (l && r && l->val != r->val)) {
            return false;
        }

        else {
            return dfs(l->left,r->right) && dfs(l->right,r->left);
        }
    }
};

二叉树的直径

给你一棵二叉树的根节点,返回该树的 直径 。

二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。

两节点之间路径的 长度 由它们之间边数表示。

cpp 复制代码
/**
 * 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:
    int ans = 0;
    int diameterOfBinaryTree(TreeNode* root) {
        if(!root) return 0;
        int l  = maxHeight(root->left);
        int r = maxHeight(root->right);
        ans = max(l+r,ans);
        diameterOfBinaryTree(root->left);
        diameterOfBinaryTree(root->right);
        return ans;
    }

    int maxHeight(TreeNode* root){
        if(!root) return 0;
        int l = maxHeight(root->left);
        int r = maxHeight(root->right);
        return 1 + max(l,r);
    }
};

二叉树的层序遍历

给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。

cpp 复制代码
/**
 * 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) {
        if(!root) return {};
        queue<TreeNode*> q;
        vector<vector<int>> ans;
        q.push(root);
        TreeNode* cur = root;
        while(!q.empty()){
            vector<int> temp;
            int n = q.size();
            for(int i = 0;i < n;i++){
                cur = q.front();
                q.pop();
                temp.push_back(cur->val);
                if(cur->left) q.push(cur->left);
                if(cur->right) q.push(cur->right);
            }
            ans.push_back(temp);
        }
        return ans;
    }
};

将有序数组转换为二叉搜索树

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵

平衡二叉搜索树。

cpp 复制代码
/**
 * 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:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
       return dfs(nums,0,nums.size()-1); 
    }

    TreeNode* dfs(vector<int> &nums,int l,int r){
        if(l > r) return nullptr;
        int mid = (l + r)/2;
        TreeNode* root = new TreeNode();
        root->left = dfs(nums,l,mid-1);
        root->val = nums[mid];
        root->right = dfs(nums,mid+1,r);
        return root;
    }
};

验证二叉搜索树

给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。

有效 二叉搜索树定义如下:

  • 节点的左子树只包含 小于 当前节点的数。
  • 节点的右子树只包含 大于 当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。
cpp 复制代码
/**
 * 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:
    long long pre = LLONG_MIN;
    bool isValidBST(TreeNode* root) {
        if(!root) return true;
        if(!isValidBST(root->left)) return false;
        if(pre >= root->val) return false;
        pre = root->val;
        return isValidBST(root->right);
    }
};

二叉搜索树中第K小的元素

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 小的元素(从 1 开始计数)。

cpp 复制代码
/**
 * 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:
    int count = 0,ans;
    int kthSmallest(TreeNode* root, int k) {
        count = k;
        dfs(root);
        return ans;
    }

    void dfs(TreeNode* root){
        if(!root || !count) return;
        dfs(root->left);
        count--;
        if(count == 0){
            ans = root->val;
        }
        dfs(root->right);
    }
};

二叉树展开为链表

给你二叉树的根结点 root ,请你将它展开为一个单链表:

  • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。
  • 展开后的单链表应该与二叉树 先序遍历 顺序相同。
cpp 复制代码
/**
 * 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 flatten(TreeNode* root) {
        if(!root) return;
        TreeNode* cur = root;
        while(cur) {
            cout<<cur->val<<endl;
            if(cur->left){
                TreeNode* t = cur->left;
                while(t->right) t = t->right;
                t->right = cur->right;
                cur->right = cur->left;
                cur->left = nullptr;
            }
            cur = cur->right;
        }
        return;
    }
};

将前序与中序遍历序列构造二叉树

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

cpp 复制代码
/**
 * 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:
    unordered_map<int,int> hash;
    TreeNode* build(vector<int>& pre,vector<int>& in,int pl,int pr,int il,int ir){
        if(pl > pr || ir < il){
            return nullptr;
        }
        TreeNode* root = new TreeNode(pre[pl]);
        int pos = hash[pre[pl]];
        root->left = build(pre,in,pl+1,pl+pos-il,il,pos-1);
        root->right = build(pre,in,pl+pos-il+1,pr,pos+1,ir);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int n = preorder.size();
        for(int i = 0;i < n;i++){
            hash[inorder[i]] = i;
        }
        return build(preorder,inorder,0,n-1,0,n-1);
    }
};

二叉树的最近公共祖先

给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:"对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。"

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(!root) return root;
        if(root == p || root == q) return root;
        TreeNode* left = lowestCommonAncestor(root->left,p,q);
        TreeNode* right = lowestCommonAncestor(root->right,p,q);
        if(!left && right) return right;
        if(!right && left) return left;
        if(left && right) return root;
        return NULL;
    }
};

二叉树中的最大路径和

二叉树中的 路径 被定义为一条节点序列,序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。

路径和 是路径中各节点值的总和。

给你一个二叉树的根节点 root ,返回其 最大路径和 。

cpp 复制代码
/**
 * 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:
    int ans = INT_MIN;
    int maxPathSum(TreeNode* root) {
        dfs(root);
        return ans;
    }
    int dfs(TreeNode* root){
        if(!root) return 0;
        int left = max(0,dfs(root->left));
        int right = max(0,dfs(root->right));
        ans = max(ans,root->val + left + right);
        return root->val + max(left,right);
    }
};

路径总和III

给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。

路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。

cpp 复制代码
/**
 * 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:
    int RootSum(TreeNode* root,long long targetSum){
        if(!root) return 0;
        int ans = 0;
        if(root->val == targetSum) ans++;
        ans += RootSum(root->left,targetSum-root->val);
        ans += RootSum(root->right,targetSum-root->val);
        return ans;
    }

    int pathSum(TreeNode* root, int targetSum) {
        if(!root) return 0;
        int ans = RootSum(root,targetSum);
        ans += pathSum(root->left,targetSum);
        ans += pathSum(root->right,targetSum);
        return ans;
    }
};
相关推荐
2401_843785239 分钟前
C语言 扫雷程序设计
c语言·算法
qystca12 分钟前
炸弹 (boom.c)
算法
pen-ai15 分钟前
【LeetCode】4. 去重的效率提升
算法·leetcode·哈希算法
Tisfy16 分钟前
LeetCode 3019.按键变更的次数:遍历(转小写)
算法·leetcode·字符串·题解·遍历
无限码力26 分钟前
目标值子矩阵的数量
c++·算法·矩阵
ChoSeitaku1 小时前
No.6十六届蓝桥杯备战|赋值操作符|连续赋值|复合赋值|类型转换|强制|混合|赋值(C++)
c++·算法·蓝桥杯
勤劳的进取家1 小时前
区别:支持向量机 (SVM) 和逻辑回归
算法·支持向量机·逻辑回归
萌の鱼1 小时前
leetcode 2279. 装满石头的背包的最大数量
数据结构·c++·算法·leetcode
S-X-S2 小时前
算法解析-经典150(图论、回溯法)
算法·深度优先·图论