AVL树的定义
平衡二叉树由前苏联两位数学家GM.Adelse-Velskil、E.M.Landis提出,因此一般也称作AVL树。
AVL树从本质上说仍是一颗二叉搜索树,只是在其的基础上添加了平衡要求,使得树的高度在每次插入元素后仍可以保持O(logn)的级别。
所谓的平衡操作指的是对于AVL树的任意结点来说,其左子树和右子树的高度差的绝对值不超过1,其中左子树的高度减去右子树的高度称为该结点的平衡因子。
例如,对于下面的三棵树,根结点的平衡因子分别是 -1、2、-2
基本操作函数
1.结构体
因为需要对每个结点计算平衡因子,所以需要在树的结构中加入一个变量height用来记录以当前结点为根节点的子树的高度
struct node{
int data,height;//权值和高度
node* l,*r;//左右孩子地址
};
2.获取当前结点root的高度
空树的高度为0,叶子结点高度为1
int getheight(node* root)
{
if(root==NULL)return 0;
else return root->height;
}
3.求平衡因子
每个结点的平衡因子是左子树高度减去右子树高度
int getbalancefactor(node* root)
{
return gethight(root->l)-getheight(root->r);
}
4.更新结点高度
在插入结点或者旋转操作后树高会改变,所以在执行相应的操作时,需要实时的更新每个结点的高度
void updataheight(node* &root)
{
//当前结点的高度为左右子树中较大高度+1
root->height=max(getheight(root->l),getheight(root->r))+1;
}
旋转操作
1.左旋
完成旋转一共需要三步:
1.让B的左子树成为A的右子树
2.让A成为B的左子树
3.将根节点设定为结点B
void leftrotation(node* &root)
{
node* temp=root->r;
root->r=temp->l;
temp->l=root;
updateheight(root);
updateheight(temp);
root=temp;
}
2.右旋
右旋和左旋是对称的过程,从本质上来看,他们互为逆操作
相应的步骤:
1.让A的右子树成为B的左子树
2.让B成为A的右子树
3.将根节点设定为结点A
void rightrotation(node* &root)
{
node* temp=root->l;
root->l=temp->r;
temp->r=root;
updateheight(root);
updateheight(temp);
root=temp;
}
插入操作
每插入一个结点,一定会有结点的平衡因子发生变化,所以每插入一个结点,都需要更新一下树高,当某结点的平衡因子等于2或者-2时,以该结点为根结点的子树发生失衡,需要旋转调整。在这基础上我们还需判断其相应的子树,以确定相应的翻转操作。
下面我们先讨论平衡因子为2的情况:
对于根结点A,其平衡因子都为2,但是对于A的左子树B,可以发现左边的平衡因子为1,右边的为-1;对于这两种树型,左边的称为LL型树,右边的为LR型树
树型 | 调整方法 |
---|---|
LL | 对根结点root右旋 |
LR | 先对root->l 左旋,使之变为LL型树,再对root右旋 |
然后看对于平衡因子为-2的情况
左边为RR型树,右边为RL型树
树型 | 调整方法 |
---|---|
RR | 对根结点root左旋 |
RL | 先对root->r右旋使之转为RR型树,然后对root左旋 |
void insert(node* &root,int x)
{
if(root==NULL)
{
root=new node;
root->data=x;
root->height=1;//叶子结点高度为1
root->l=root->r=NULL;
return;
}
if(x<root->data)
{
insert(root->l,x);
updataheight(root);
if(getbalancefactor(root)==2)
{
if(getbalancefactor(root->l)==1)//LL型树
{
right_rotation(root);
}
else//LR型树
{
left_rotation(root->l);
right_rotation(root);
}
}
}
else
{
insert(root->r,x);
updataheight(root);
if(getbalancefactor(root)==-2)
{
if(getbalancefactor(root->r)==-1)//RR型树
left_rotation(root);
else//RL型树
{
right_rotation(root->r);
left_rotation(root);
}
}
}
}