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;
}