手撕AVL树-N*!!!

二叉排序树的基础知识

名称:二叉排序树、二叉搜索树
性质:
1、左子树<根结点
2、右子树>根结点
用途:解决与排名相关的检索要求

构造二叉排序树:

/*
 * @Author: mikey.peng 
 * @Date: 2021-08-08 19:52:23 
 * @Last Modified by:   mikey.peng 
 * @Last Modified time: 2021-08-08 19:52:23 
 */
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
using namespace std;
//结构定义
typedef struct Node{
    Node(int key=0,Node *left=nullptr,Node *right=nullptr)
    :key(key),left(left),right(right){}
    int key;
    Node *left,*right;
}Node;


//结构操作

//获取新节点
Node *getNewNode(int key){
    return new Node(key);
}    

//插入新节点(插入后返回新的根结点的结点地址)
Node *insert(Node *root,int key){
    if(root == nullptr) return getNewNode(key);
    if(root->key == key) return root;
    if(key<root->key)root->left = insert(root->left,key);//向左子树中插入数值
    else root->right = insert(root->right,key);
    return root;
}

//找到当前节点(两个度的)的前驱结点
Node *predecessor(Node *root){
    Node *temp = root->left;
    while(temp->right)temp = temp->right;
    return temp;
}
//删除操作 //erase是干掉单个结点,clear是干掉整颗树
Node *erase(Node *root,int key){
    if(root == nullptr) return root;
    if(key < root->key){
        root->left = erase(root->left,key);
    }else if(root->key<key){
        root->right = erase(root->right,key);
    }else{
        //当前节点就是要删除的结点要分成三种情况来讨论:
        //1.度为0的
        if(root->left == nullptr&& root->right == nullptr){
            delete root;
            return nullptr;
        }
        //2.度为1的
        else if(root->right==nullptr || root->left==nullptr){
            //如果删除度为1的需要先找到当前节点的唯一子孩子temp
            Node *temp = root->left ? root->left:root->right;
            delete root;
            return temp;
        }
        //3.度为2的
        else{
            //首先需要找到当前节点的前驱节点或者后继结点
            Node *temp = predecessor(root);
            //将前驱结点的值赋值给当前节点
            root->key = temp->key;
            //到左子树中将当前节点给它删掉
            root->left = erase(root->left,temp->key);
        }
    }
    return root;

}

//销毁操作
void clear(Node *root){
    if(root == nullptr) return ;
    clear(root->left);
    clear(root->right);
    delete root;
    return ;
}

void output(Node *root){
    if(root == nullptr)return ;
    output(root->left);
    cout<<root->key<<" ";
    output(root->right);
    return ;
}

int main(){
    int op,val;
    Node *root = nullptr;
    while(cin>> op >> val){
        switch(op){//op=0执行的是插入操作,op=1执行的是删除操作
            case 0: root = insert(root,val);break;
            case 1: root = erase(root,val);break;
        }   
        output(root);//中序遍历方式输出二叉排序树
        cout<<endl;
    }
    return 0;
}

AVL树的基础知识

发明者
G.M.Adelson-Velsky
E.M.Landis
年代:1962年(59岁)
性质
|H(left)-H(right)|<=1
优点:
由于对每个节点的左右子树的树高做了限制,所以整棵树不会退化成一个链表
使用虚拟空间点NIL 实现AVL树定义

/*
 * @Author: mikey.zhaopeng 
 * @Date: 2021-08-09 20:51:47 
 * @Last Modified by: mikey.zhaopeng
 * @Last Modified time: 2021-08-09 22:46:55
 */
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<algorithm>
#include<string>
#include<map>
#include<set>
#include<vector>
using namespace std;

//定义一个虚拟空节点用于替代空地址的 和链表中虚拟头结点作用相似 便于在处理子树空节点的情况
#define NIL (&node::__NIL)//这个NIL结点是有高度(0),有值
struct node{
    node(int key=0,int h=0,node *left=NIL,node *right=NIL)
    :key(key),h(h),left(left),right(right){}
    int key,h;//h表示当前节点所在子树的高度
    node *left,*right;
    static node __NIL;
};

node node::__NIL;
node *getNewNode(int key){
    return new node(key,1);
}

void update_height(node *root){
    // if(root->left == nullptr && root->right == nullptr) return ;
    // if(root->left == nullptr) root->h = root->right->h +1; 
    // else if(root->right == nullptr) root->h = root->left->h+1;
    //使用NIL虚拟空节点上面这些代码都可以没有
    // else        
     root->h = max(root->left->h,root->right->h)+1;
    return ;
}
node *left_rotate(node *root){
    node *new_root = root->right;
    root->right  = new_root->left;
    new_root->left = root;
    update_height(root);
    update_height(new_root);
    return new_root;
}
node *right_rotate(node *root){
    node *new_root = root->left;
    root->left = new_root->right;
    new_root->right = root;
    update_height(root);
    update_height(new_root);
    return new_root;
}
node *maintain(node *root){
    if(abs(root->left->h-root->right->h)<2) return root;
    //此时当前节点需要调整
    //首先区分第一个字母是L还是R  此时L
    if(root->left->h > root->right->h){
        //判断第二个字母是L还是R  此时R
        if(root->left->right->h > root->left->left->h){
            //LR 先进行小左旋在进行大右旋
            root->left = left_rotate(root->left);
        }
        root = right_rotate(root);
    }else {
        if(root->right->left->h > root->right->right->h){
            root->right = right_rotate(root->right);
        }
        root = left_rotate(root);
    }
    return root;

}

node *insert(node *root,int key){
    if(root == NIL) return getNewNode(key);
    if(root->key == key) return root;
    if(root->key > key) root->left = insert(root->left,key);
    else root->right = insert(root->right,key);
    update_height(root);//重新计算当前节点的高度
    return maintain(root);
}

//找到当前节点(两个度的)的前驱结点
node *predecessor(node *root){
    node *temp = root->left;
    while(temp->right)temp = temp->right;
    return temp;
}
node *erase(node *root,int key){
    if(root == NIL) return root;
    if(key<root->key){
        root->left = erase(root->left,key);
    }else if(key > root->key) {
        root->right = erase(root->right,key);
    }else{
        //这里度为0和度为1为一种情况 因为temp返回的是度为0的结点地址
        if(root->left == NIL || root->right == NIL){
            node *temp = root->left =NIL? root->right:root->left;
            delete root;
            return temp;
        }else{
            //删除的是度为2的结点地址
            node *temp = predecessor(root);
            root->key = temp->key;
            root->left = erase(root->left,temp->key);
        }
    }
    update_height(root);
    return maintain(root);

}

//销毁整棵树
void clear(node *root){
    if(root==NIL) return ;
    clear(root->left);
    clear(root->right);
    cout << "delete :" << root->key << endl;
    delete root;
    return ;
}
void print(node * root){
    printf("(%d[%d] | %d,%d)\n",root->key,root->h,root->left->key,root->right->key);
    return ;
}
void output(node * root){
    if(root == NIL) return ;
    print(root);
    output(root->left);
    output(root->right);
    return ;
}
int main(){
    int op ,val;
    node *root = NIL;
    while(cin>>op>>val){
        switch(op){
            case 0: root = insert(root,val);break;
            case 1: root = erase(root,val);break;
        }
        cout<<endl<<"============avl tree print============"<<endl;
        output(root);
        cout<<endl<<"============tree print done==========="<<endl;
    
    }

    clear(root);
    return 0;
}

leetcode - 面试题 04.06. 后继者

class Solution {
public:
    TreeNode *pre;
    TreeNode *inorder(TreeNode *root,TreeNode *p){
        if(root == nullptr) return nullptr;
        TreeNode *node;
        if(node = inorder(root->left,p)) return node;//如果左子树不为空返回
        //pre在这里就会从小到大的访问到每一个结点
        if(pre == p) return root;
        pre = root;
        if(node=inorder(root->right,p))return node;//如果右子树不为空则返回
        return nullptr;
    }
    TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) {
        pre =nullptr;
        return inorder(root,p);
    }
};
  1. 将二叉搜索树变平衡
/**
 * 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 getNodes(TreeNode *root,vector<TreeNode *> &nodes){
        if(root == nullptr) return ;
        getNodes(root->left,nodes);
        nodes.push_back(root);
        getNodes(root->right,nodes);
        return ;
    }
    TreeNode *buildTree(vector<TreeNode *> &nodes,int l,int r){
        if(l>r) return nullptr;
        int mid = (l+r)>>1;
        TreeNode *root = nodes[mid];
        root->left = buildTree(nodes,l,mid-1);
        root->right = buildTree(nodes,mid+1,r);
        return root;
    }
    TreeNode* balanceBST(TreeNode* root) {
        vector<TreeNode *> nodes; //存储这棵树的结点
        getNodes(root,nodes);//按照中序遍历获取到每一个结点
        return buildTree(nodes,0,nodes.size()-1);//根据动态链表中的结点来建立树,返回的是新建立的树的根结点的地址
    }
}; 

leetcode-108. 将有序数组转换为二叉搜索树

/**
 * 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 *buildTree(vector<int> &nums,int l,int r){
        if(l>r) return nullptr;
        int mid = (l+r)>>1;
        TreeNode * root = new TreeNode(nums[mid]);
        root->left = buildTree(nums,l,mid-1);
        root->right = buildTree(nums,mid+1,r);
        return root;

    }
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        return buildTree(nums,0,nums.size()-1);
    }
};

leetcode-98. 验证二叉搜索树

class Solution {
public:
    int* last = NULL;
    TreeNode *pre;
    bool inorder(TreeNode *root){
        if(root == nullptr) return true;
        if(!inorder(root->left))return false;
        if (pre != nullptr && root->val<=pre->val){
            return false;
        }
        pre = root;
        if(!inorder(root->right))return false;
        return true;
    }

    bool isValidBST(TreeNode* root) {
    //fa 1
        pre = nullptr;
        return inorder(root);
    }
};

leetcode-501. 二叉搜索树中的众数

class Solution {
public:
TreeNode *now;//用于记录当前比较节点的值
int  cnt,max_cnt; 
    void getResult(TreeNode *root,vector<int>&ret){
        if(root == nullptr) return ;
        getResult(root->left,ret);
        if(now->val == root->val){
            cnt+=1;
        }else{
            now = root;
            cnt = 1;
        }
        if(max_cnt == cnt){
            ret.push_back(now->val);
        }else if(cnt>max_cnt){//说明之前找到的都不是最大的众数
            max_cnt = cnt;
            ret.clear();
            ret.push_back(now->val);
        }
        getResult(root->right,ret);
        return ;
    }
    vector<int> findMode(TreeNode* root) {
        int cnt = max_cnt = 0;
        now = root;
        vector<int> ret;//存储所有的众数
        getResult(root,ret);
        return ret;
    }
};

leetcode-面试题 17.12. BiNode

/**
 * 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 *head,*pre;
    TreeNode* convertBiNode(TreeNode* root) {
        head = pre = NULL;
        inoreder(root);
        return head;
    }
    void inoreder(TreeNode *root){
        if(root==NULL) return ;
        inoreder(root->left);
        if(pre == NULL){
            //当前是第一个结点
            head = root;
        }else{
            //让前一个节点向后指向当前节点
            pre->right = root;
        }
        root->left = NULL;
        pre = root;
        inoreder(root->right);
        return ;
    }
};

leetcode-剑指 Offer 33. 二叉搜索树的后序遍历序列

class Solution {
public:
    int pre;//记录前一个元素的下标
    bool verifyPostorder(vector<int>& postorder) {
        pre=-1;
        return inorder(postorder,0,postorder.size()-1);
    }
    bool inorder(vector<int> &nums,int l,int r){
        if(l>r) return true;//空树满足二叉排序树的性质
        int ind=l;
        while(nums[ind]<nums[r])++ind;
        if(!inorder(nums,l,ind-1)) return false;
        if(pre!=-1 && nums[r]<=nums[pre]) return false; 
        pre = r;//这里r就是根结点
        if(!inorder(nums,ind,r-1)) return false;
        return true;
    }
};

leetcode-1008. 前序遍历构造二叉搜索树

/**
 * 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 *buildTree(vector<int>& nums,int l,int r){
        if(l>r) return nullptr;
        int ind = l+1;
        while(ind<=r && nums[ind]<nums[l]) ++ind;
        TreeNode *root = new TreeNode(nums[l]);
        root-> left = buildTree(nums,l+1,ind-1);
        root->right = buildTree(nums,ind,r);
        return root;
    }
    TreeNode* bstFromPreorder(vector<int>& preorder) {
        return buildTree(preorder,0,preorder.size()-1);
    }
};

leetcode-面试题 04.09. 二叉搜索树序列

/**
 * 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:
    void mergeSequences(
        vector<int>&l,int lind,vector<int>&r,int rind,
        vector<int>&buff,vector<vector<int>>&ret){
        if(lind == l.size() && rind == r.size()){
            ret.push_back(buff);
            return ;
        }
        if(lind<l.size()){//说明左子树序列中还有元素,就将左子树序列拿出一个元素添加到buff数组中
            buff.push_back(l[lind]);
            mergeSequences(l,lind+1,r,rind,buff,ret);
            buff.pop_back();//将buff数组还原成原来没有添加的样子
        }
        if(rind<r.size()){
            buff.push_back(r[rind]);
            mergeSequences(l,lind,r,rind+1,buff,ret);
            buff.pop_back();
        }
        return ;
    }
    vector<vector<int>> BSTSequences(TreeNode* root) {
        vector<vector<int>> ret;//结果数组
        if(root==nullptr){
            ret.push_back(vector<int>());//如果为空则放入一个空数组
            return ret;
        }
        //从这开始获取左右子树中的合法序列
        vector<vector<int>> l_arr=BSTSequences(root->left);
        vector<vector<int>> r_arr=BSTSequences(root->right);

        //进行排列组合:左子树中的每一个序列,配上右子树上的每一个序列
        for(auto l:l_arr){
            for(auto r:r_arr){
                vector<int>buff;
                buff.push_back(root->val);
                mergeSequences(l,0,r,0,buff,ret);//传左右子树的序列,还有左右子树分别选择了多少个元素了,缓冲区,结果数组
            }
        }
        return ret;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值