【数据结构与算法】AVL平衡二叉树

本文详细阐述了AVL树的平衡因子概念,包括其计算方法以及四种类型的不平衡情况及其处理策略。通过右旋和左旋操作演示了如何通过调整来保持树的平衡,并介绍了插入节点后的平衡因子更新。核心内容涉及LL、LR、RR和RL类型的旋转算法及平衡调整过程。
摘要由CSDN通过智能技术生成

AVL树

平衡二叉树由于自动调整左右子树的平衡,可以保证在不断插入删除数据时有着较高的查找效率

平衡因子BF(Balance Factor)


BF=左子树高度减右子树高度
对于平衡二叉树来说,平衡因子只可能为{0,1,-1},绝对值一旦大于1就会造成不平衡。


原理与处理方法
共有四种类型:LL , LR , RR , RL,解决这四种类型有相应的办法。
1.	LL
(1)	情形:插入结点在距离最近的不平横根结点(P)(即平衡因子绝对值大于1)的左子树(L)的左子树(ll)上
(2)	方法:先只关注P L ll这三个结点,进行“右旋”(操作名字无所谓,只要把处在中间的放最上面即可,两边和L比较,小的放左边,大的放右边),将L作为根结点,替代P的位置(P原来的双亲结点连在L上);P作为L的右子树,ll作为L的左子树,原L的右子树挂在P的左子树上,旋转结束。
2.	LR
(1)	情形:插入结点在距离最近的不平衡根结点(P)(即平衡因子绝对值大于1)的左子树(L)的右子树(lr)上
(2)	方法:先只关注P L lr 这三个结点,先左旋再右旋(还是那句话,名字无所谓,选择中间的lr放在最上面,然后把P和L与lr比较,小的放左边,大的放右边,因上述操作去除的子树分别以二叉查找树插入的方法挂在合适的结点,当然这也是有规律的)
3.	RR
(1)	情形:插入结点在距离最近的不平衡根结点(P)(即平衡因子绝对值大于1)的右子树(R)的右子树(rr)上。
(2)	方法:先只关注P 	R rr这三个结点,进行“左旋”(操作名字无所谓,只要把处在中间的放最上面即可,两边和R比较,小的放左边,大的放右边),将R作为根结点,替代P的位置(P原来的双亲结点连在R上);P作为R的左子树,rr作为R的右子树,原R的左子树挂在P的右子树上,旋转结束。
4.	RL
(3)	情形:插入结点在距离最近的不平衡根结点(P)(即平衡因子绝对值大于1)的右子树(R)的左子树(rl)上
(4)	方法:先只关注P R rl 这三个结点,先右旋再左旋(还是那句话,名字无所谓,选择中间的rl放在最上面,然后把P和R与rl比较,小的放左边,大的放右边,因上述操作去除的子树分别以二叉查找树插入的方法挂在合适的结点,当然这也是有规律的)


平衡因子的重新计算

当我们经过旋转操作将二叉树重新平衡后,也同时要把平衡因子重新赋值。下面给出了各种情况和调整后的平衡因子。


#define LH +1
#define EH  0
#define RH -1
我们根据不同的结构选择不同的调整策略

数据结构

struct avlnode
{
    int data;
    int bf;
    avlnode* lchild,*rchild;
};

LL型

void r_rotate(avlnode* &P)//右旋操作 LL型
{
    avlnode* L=P->lchild;
    P->lchild=L->rchild;
    L->rchild=P;
    P=L;
}

RR型

void l_rotate(avlnode* &P)//左旋操作 RR型
{
    avlnode* R=P->rchild;
    P->rchild=R->lchild;
    R->lchild=P;
    P=R;
}

LR和LL型

void LeftBalance(avlnode* &T)//左子树平衡操作 下分 LL和 LR型
{
    avlnode *L,*Lr;
    L=T->lchild;
    switch(L->bf)
    {
        case LH://LL
            L->bf=T->bf=EH;
            r_rotate(T);
            break;
        case RH://LR
            Lr=L->rchild;
            switch (Lr->bf)
            {

                case LH:
                    L->bf=EH;
                    T->bf=RH;
                    break;
                case EH:
                    L->bf=T->bf=EH;
                    break;
                case RH:
                    L->bf=LH;
                    T->bf=EH;
                    break;
            }
            Lr->bf=EH;
            l_rotate(T->lchild);
            r_rotate(T);
            break;
    }
}

RR和RL型

void RightBalance(avlnode* &T)
{
    avlnode *R,*Rl;
    R=T->rchild;
    switch(R->bf)
    {
        case RH://RR
            R->bf=T->bf=EH;
            l_rotate(T);
            break;
        case LH://RL
            Rl=R->lchild;
            switch (Rl->bf)
            {
                case RH:
                    R->bf=EH;
                    T->bf=LH;
                    break;
                case EH:
                    R->bf=T->bf=EH;
                    break;
                case LH:
                    T->bf=EH;
                    R->bf=RH;
                    break;
            }
            Rl->bf=EH;
            r_rotate(T->rchild);
            l_rotate(T);
            break;
    }
}

插入函数

bool InsertAVL(avlnode *&T,int e,bool &taller)
{
    if(!T)//找到插入位置,开始插入
    {
        T=(avlnode*)malloc(sizeof(avlnode));
        T->bf=EH;
        T->data=e;
        T->lchild=T->rchild=NULL;
        taller=true;//taller为是否检查平衡的标志
    }
    else
    {
        if(e==T->data)
        {
            taller=false;
            return false;
        }
        if(e<T->data)
        {
            if(!InsertAVL(T->lchild,e,taller))
            {
                return false;
            }
            if(taller)//此时的T的BF还未更新
            {
                switch(T->bf)//插入到T的左子树中
                {
                    case LH:
                        LeftBalance(T);
                        taller=false;
                        break;
                    case EH:
                        T->bf=LH;
                        taller=true;
                        break;
                    case RH:
                        T->bf=EH;
                        taller=false;
                        break;
                }
            }
        }
        else
        {
            if(!InsertAVL(T->rchild,e,taller))
            {
                return false;
            }
            if(taller)
            {
                switch(T->bf)
                {
                    case RH:
                        RightBalance(T);
                        taller=false;
                        break;
                    case EH:
                        T->bf=RH;
                        taller=true;
                        break;
                    case LH:
                        T->bf=EH;
                        taller=false;
                        break;
                }
            }
        }
    }
    return true;
}
  • 关于平衡因子的分配比较抽象,可以进行推理证明
  • 左旋和右旋的操作中需注意传入的参数是指针的引用,(二级指针也可,但形式较复杂;也可以直接返回指针,总而言之就是为了修改指针的指向,从而和父结点连接)

完整代码

#define LH +1
#define EH  0
#define RH -1
struct avlnode
{
    int data;
    int bf;
    avlnode* lchild,*rchild;
};
void r_rotate(avlnode* &P)//右旋操作 LL型
{
    avlnode* L=P->lchild;
    P->lchild=L->rchild;
    L->rchild=P;
    P=L;
}
void l_rotate(avlnode* &P)//左旋操作 RR型
{
    avlnode* R=P->rchild;
    P->rchild=R->lchild;
    R->lchild=P;
    P=R;
}
void LeftBalance(avlnode* &T)//左子树平衡操作 下分 LL和 LR型
{
    avlnode *L,*Lr;
    L=T->lchild;
    switch(L->bf)
    {
        case LH://LL
            L->bf=T->bf=EH;
            r_rotate(T);
            break;
        case RH://LR
            Lr=L->rchild;
            switch (Lr->bf)
            {

                case LH:
                    L->bf=EH;
                    T->bf=RH;
                    break;
                case EH:
                    L->bf=T->bf=EH;
                    break;
                case RH:
                    L->bf=LH;
                    T->bf=EH;
                    break;
            }
            Lr->bf=EH;
            l_rotate(T->lchild);
            r_rotate(T);
            break;
    }
}
void RightBalance(avlnode* &T)
{
    avlnode *R,*Rl;
    R=T->rchild;
    switch(R->bf)
    {
        case RH://RR
            R->bf=T->bf=EH;
            l_rotate(T);
            break;
        case LH://RL
            Rl=R->lchild;
            switch (Rl->bf)
            {
                case RH:
                    R->bf=EH;
                    T->bf=LH;
                    break;
                case EH:
                    R->bf=T->bf=EH;
                    break;
                case LH:
                    T->bf=EH;
                    R->bf=RH;
                    break;
            }
            Rl->bf=EH;
            r_rotate(T->rchild);
            l_rotate(T);
            break;
    }
}
bool InsertAVL(avlnode *&T,int e,bool &taller)
{
    if(!T)//找到插入位置,开始插入
    {
        T=(avlnode*)malloc(sizeof(avlnode));
        T->bf=EH;
        T->data=e;
        T->lchild=T->rchild=NULL;
        taller=true;//taller为是否检查平衡的标志
    }
    else
    {
        if(e==T->data)
        {
            taller=false;
            return false;
        }
        if(e<T->data)
        {
            if(!InsertAVL(T->lchild,e,taller))
            {
                return false;
            }
            if(taller)//此时的T的BF还未更新
            {
                switch(T->bf)//插入到T的左子树中
                {
                    case LH:
                        LeftBalance(T);
                        taller=false;
                        break;
                    case EH:
                        T->bf=LH;
                        taller=true;
                        break;
                    case RH:
                        T->bf=EH;
                        taller=false;
                        break;
                }
            }
        }
        else
        {
            if(!InsertAVL(T->rchild,e,taller))
            {
                return false;
            }
            if(taller)
            {
                switch(T->bf)
                {
                    case RH:
                        RightBalance(T);
                        taller=false;
                        break;
                    case EH:
                        T->bf=RH;
                        taller=true;
                        break;
                    case LH:
                        T->bf=EH;
                        taller=false;
                        break;
                }
            }
        }
    }
    return true;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值