二叉平衡树AVL插入删除操作的实现

操作有左旋rr,右旋ll,左右旋lr,右左旋rl,插入新节点insert(四种旋转都涉及,而且左右旋和右左旋只有插入时才会用到),平衡操作balance(确保一个点平衡,要么不旋转要么左旋要么右旋,只在删除时使用),删除erase(删除一个节点并平衡整棵树),另外两个dfs_show_me_the_tree和inorder在main中作为检验的方法。

#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
struct node
{
    node*lch,*rch;
    int key;
    node(int x):key(x){lch=rch=nullptr;}
};
using ptr=node*;
//取子树p的深度,检验平衡性时使用
int deep(ptr p)
{
    if(!p)return 0;
    return max(deep(p->lch),deep(p->rch))+1;
}
//ll指插入左子树的左子树失衡,要右旋,这里“ll”跟“右”在字面上是相反的
ptr ll(ptr p)
{
    ptr l=p->lch;
    p->lch=l->rch,l->rch=p;
    return l;
}
//rr指插入右子树的右子树失衡,要左旋,这里“rr”跟“左”在字面上是相反的
ptr rr(ptr p)
{
    ptr r=p->rch;
    p->rch=r->lch,r->lch=p;
    return r;
}
//rl指插入右子树的左子树失衡,右旋右子树再左旋自己,这里“r-l”跟“右-左”恰巧一样
ptr rl(ptr p)
{
    p->rch=ll(p->rch);
    return rr(p);
}
//lr指插入左子树的右子树失衡,左旋左子树再右旋自己,这里“l-r”跟“左-右”恰巧一样
ptr lr(ptr p)
{
    p->lch=rr(p->lch);
    return ll(p);
}
//在erase中使用的小工具
ptr balance(ptr p)
{
    if(deep(p->lch)-deep(p->rch)==2)
        return ll(p);
    if(deep(p->rch)-deep(p->lch)==2)
        return rr(p);
    return p;
}
ptr insert(ptr p,int x)
{
    if(!p)return new node(x);
    //插入,如果失衡返回平衡后的p,这里不能使用balance因为balance不需要lr,rl,而这里需要
    if(x<p->key)
    {
        p->lch=insert(p->lch,x);
        if((deep(p->lch)-deep(p->rch))==2)
            return x<p->lch->key?ll(p):lr(p);
    }else
    {
        p->rch=insert(p->rch,x);
        if((deep(p->rch)-deep(p->lch))==2)
            return x<p->rch->key?rl(p):rr(p);
    }
    //如果没有失衡也返回p
    return p;
}
ptr erase(ptr p,int x)
{
    if(!p)return p;
    //如果在p的子树上删除,事后自然要检查p是否失衡
    if(x<p->key)p->lch=erase(p->lch,x);
    else if(x>p->key)p->rch=erase(p->rch,x);
    //x在p这个节点上分为三种情况讨论
    //p无左子树直接返回右子树,这个右子树一定没有失衡
    else if(!p->lch)
    {
        ptr r=p->rch;
        delete p;return r;
    }
    //p的左子树无右子树,如下设置后,返回p的左子树,
    //只有l可能失衡,l平衡一次
    else if(!p->lch->rch)
    {
        ptr l=p->lch;
        l->rch=p->rch;
        delete p;return balance(l);
    }
    //找到如下代码所示的lr,失去lr的l和重新设置的lr都可能失衡,l右旋一次,lr平衡一次
    else
    {
        ptr l=p->lch,lr;
        for(l=p->lch;l->rch->rch;l=l->rch);
        lr=l->rch,l->rch=lr->lch;
        //平衡l没想到好的方法,只好从上往下仔细考量
        p->lch=balance(p->lch);
        for(l=p->lch;l->rch!=lr->lch;l=l->rch)l->rch=balance(l->rch);
        //再配置好lr并平衡
        lr->lch=p->lch,lr->rch=p->rch;
        delete p;return balance(lr);
    }
    return balance(p);//该节点及其祖先节点们也不会失衡
}
void dfs_show_me_the_tree(ptr p)
{
    if(!p)return;
    if(p->lch)
        cout<<p->key<<" lch is"<<p->lch->key<<endl;
        if(p->rch)
        cout<<p->key<<" rch is"<<p->rch->key<<endl;
    dfs_show_me_the_tree(p->lch);
    dfs_show_me_the_tree(p->rch);
}
void inorder(ptr p)
{
    if(!p)return;
    inorder(p->lch);
    cout<<p->key<<' ';
    inorder(p->rch);
}
int main()
{
    vector<int>x{3,5,2,7,5,0,1,512,44,-4,2};
    ptr avl=nullptr;
    
    cout<<"the inserting process\n";
    for(int i=0;i<x.size();++i){avl=insert(avl,x[i]);inorder(avl);cout<<endl;}
   
    cout<<"\nshow the kids of each node\n";
    dfs_show_me_the_tree(avl);
    
    cout<<"\nthe deleting process\n";
    for(int i=0;i<x.size();++i){avl=erase(avl,x[i]);inorder(avl);cout<<endl;}
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值