二叉树详解 及力扣常见题型

一、二叉树的种类

1、满二叉树

        除最后一层无任何子节点外,每一层上的所有结点都有两个子结点二叉树(若深度为k,有2^k-1个节点)。

2、完全二叉树

        设一棵二叉树深度为h。除了第h层外,其它各层的结点数都达到最大个数,且第h层(最下面一层)的所有结点都连续集中在最左边,该层包含 1~ 2^h -1 个节点。。

3、二叉搜索树(二叉查找树,二叉排序树)

        二叉搜索树是有数值的,且是一个有序树, 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树 。

 二叉搜索树会出现平衡问题:

        二叉搜索树在经过多次插入与删除后,有可能导致上面右图的结构: 搜索性能已经是线性的了,所以,使用二叉搜索树还要考虑尽可能保持上面左图的结构,和避免上面右图的结构,也就是所谓的“平衡”问题 。

        为了解决这种情况,所以出现了下面我即将谈到的平衡二叉搜索树。 

4、平衡二叉搜索树 (AVL树)

        AVL树也规定了左结点小于根节点,右结点大于根节点。并且还规定了左子树和右子树的高度差不得超过1,这样保证了它不会成为线性的链表。AVL树主要就是通过左旋和右旋来解决平衡问题。

二、二叉树的创建 

//初始化列表形式,初始化节点
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){}
};

//根据数组构造完全二叉树
TreeNode *creatMytree(vector<int>& Mytree,int index,int len){
    if(index>=len)  return nullptr;
    TreeNode *t=new TreeNode(Mytree[index]);
    t->left=creatMytree(Mytree,index*2+1,len);
    t->right=creatMytree(Mytree,index*2+2,len);
    return t;
}

//根据前序遍历创建任意二叉树
TreeNode* deserialize_dfs(list<string>& dataArray){
    if(!dataArray.size() ) return nullptr;
    if(dataArray.front()=="None"){
        dataArray.erase(dataArray.begin());
        return nullptr;
    }
    TreeNode* node=new TreeNode(stoi(dataArray.front()));
    dataArray.erase(dataArray.begin());
    node->left=deserialize_dfs(dataArray);
    node->right=deserialize_dfs(dataArray);
    return node;
}

int main()
{
    //根据数组创建完全二叉树
    vector<int> Mytree={5,4,6,1,2,7,8};
    int len=Mytree.size();
    TreeNode *root=creatMytree(Mytree,0,len);

    //根据前序遍历创建任意二叉树
    list<string> dataArray={"1","2","4","None","None","None","3","None","None"};
    TreeNode *root1=deserialize_dfs(dataArray);

    getchar();
    return 0;
}

三、二叉树的遍历

二叉树的遍历有以下几种方式:

1、深度优先遍历

        前序遍历(递归法,迭代法):中左右  5 4 1 2 6 7 8

        中序遍历(递归法,迭代法):左中右  1 4 2 5 7 6 8

        后序遍历(递归法,迭代法):左右中  1 2 4 7 8 6 5

2、广度优先遍历

        层次遍历(迭代法):5 4 6 1 2 7 8

 代码如下:


//前序遍历:中左右
//1、递归法
void preorderTraversal(TreeNode *cur,vector<int>& res){
    if(!cur) return;
    res.push_back(cur->val);
    preorderTraversal(cur->left,res);
    preorderTraversal(cur->right,res);
}
//2、迭代法
void preorderStk(TreeNode *cur,vector<int>& res){
    stack<TreeNode*> stk;
    while(cur || !stk.empty()){
        while(cur){
            res.push_back(cur->val);    //中
            stk.push(cur);
            cur=cur->left;  //左
        }
        cur=stk.top();
        stk.pop();
        cur=cur->right; //右
    }
    
}

//中序遍历:左中右
//1、递归法
void inorderTraversal(TreeNode *cur,vector<int>& res){
    if(!cur) return;
    inorderTraversal(cur->left,res);
    res.push_back(cur->val);
    inorderTraversal(cur->right,res);
}
//2、迭代法
void inorderStk(TreeNode *cur,vector<int>& res){
    stack<TreeNode*> stk;
    while(cur || !stk.empty()){
        while(cur){
            stk.push(cur);
            cur=cur->left;  //左
        }
        cur=stk.top();
        stk.pop();
        res.push_back(cur->val);    //中
        cur=cur->right; //右
    }
    
}

//后序遍历:左右中
//1、递归法
void postorderTraversal(TreeNode *cur,vector<int>& res){
    if(!cur) return;
    postorderTraversal(cur->left,res);
    postorderTraversal(cur->right,res);
    res.push_back(cur->val);
}
//2、迭代法
void postorderStk(TreeNode *cur,vector<int>& res){
    stack<TreeNode*> stk;
    TreeNode* pre;
    while(cur || !stk.empty()){
        while(cur){
            stk.push(cur);
            cur=cur->left;  //左
        }
        cur=stk.top();
        stk.pop();
        if(cur->right==nullptr || cur->right==pre){//只有在右节点为空,或者右节点之前已经放进res了,才能把cur放进res
            res.push_back(cur->val);    //中
            pre=cur;
            cur=nullptr; //避免cur重复放入
        }
        else{
            stk.push(cur);//右子树还有节点没有遍历到,cur重新入栈
            cur=cur->right; //右
        }
    }
    
}

//层序遍历
vector<vector<int>> levelOrder(TreeNode *root){
    vector<vector<int>> res;
    vector<int> temp;
    queue<TreeNode*> q;
    q.push(root);
    while(!q.empty()){
        int size=q.size();
        for(int i=0;i<size;i++){
            TreeNode *node=q.front();
            q.pop();
            if(node->left){
                q.push(node->left);
            }
            if(node->right){
                q.push(node->right);
            }
            temp.push_back(node->val);
        }
        res.push_back(temp);
        temp.clear();
    }
    return res;
} 

四、力扣常见二叉树有关题型

101. 对称二叉树

//判断是否是对称二叉树
class Solution {
public:
    bool compare(TreeNode* l,TreeNode* r){
        if(!l&&!r) return true;
        else if(!l||!r) return false;
        return (l->val==r->val) && compare(l->left,r->right) && compare(l->right,r->left);
    }
    bool isSymmetric(TreeNode* root) {
        return compare(root,root);
    }
};

104. 二叉树的最大深度

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(!root) return 0;
        return max(maxDepth(root->left),maxDepth(root->right))+1;
    }
};

226. 翻转二叉树

class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {
        if(!root) return nullptr;
        swap(root->left,root->right);
        invertTree(root->left);
        invertTree(root->right);
        return root;
    }
};

110. 平衡二叉树

//判断是否是平衡二叉树
class Solution {
public:
    int depth(TreeNode* root){
        if(!root) return 0;
        return max(depth(root->left),depth(root->right))+1;
    }
    bool isBalanced(TreeNode* root) {
        if(!root) return true;
        return (abs(depth(root->left)-depth(root->right))<=1) && isBalanced(root->left) && isBalanced(root->right);
    }
};

98. 验证二叉搜索树

class Solution {
public:
    bool search(TreeNode* root,long long low,long long high){
        if(!root)
            return true;
        if(root->val>=high||root->val<=low)
            return false;
        return search(root->left,low,root->val)&&search(root->right,root->val,high);
    }
    bool isValidBST(TreeNode* root) {
        return search(root,LONG_MIN,LONG_MAX);
    }
};

 617. 合并二叉树

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if(root1==nullptr)  return root2;
        if(root2==nullptr)  return root1;
        TreeNode* merged=new TreeNode(root1->val+root2->val);
        merged->left=mergeTrees(root1->left,root2->left);
        merged->right=mergeTrees(root1->right,root2->right);
        return merged;
    }
};

 114. 二叉树展开为链表

class Solution {
public:
    void flatten(TreeNode* root) {
        vector<TreeNode*>l;
        preorderTraversal(root,l);
        int size=l.size();
        for(int i=1;i<size;i++)
        {
            TreeNode *pre=l[i-1],*cur=l[i];
            pre->left=nullptr;
            pre->right=cur;
        }
    }
    void preorderTraversal(TreeNode* root,vector<TreeNode*> &l) {
        if(!root)
            return;
        l.push_back(root);
        preorderTraversal(root->left,l);
        preorderTraversal(root->right,l);
    }
};

105. 从前序与中序遍历序列构造二叉树

class Solution {
public:
    TreeNode* myTree(const unordered_map<int,int>& hashmap,vector<int>& preorder, vector<int>& inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
        if(preorder_left>preorder_right) return nullptr;
        int preorder_root=preorder[preorder_left];
        int pIndex=hashmap.at(preorder_root);
        TreeNode* root=new TreeNode(preorder_root);
        int left_size=pIndex-inorder_left;
        root->left=myTree(hashmap,preorder,inorder,preorder_left+1,preorder_left+left_size,inorder_left,pIndex-1);
        root->right=myTree(hashmap,preorder,inorder,preorder_left+left_size+1,preorder_right,pIndex+1,inorder_right);
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        unordered_map<int,int> hashmap;
        for(int i=0;i<inorder.size();i++){
            hashmap[inorder[i]]=i;
        }
        return myTree(hashmap,preorder,inorder,0,preorder.size()-1,0,inorder.size()-1);
    }
};

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值