1.平衡二叉树(AVL树)的定义
AVL树是一种自平衡二叉查找树,树中任何结点的两个子树高度之差的绝对值不超过1,也成为高度平衡树,左子树与右子树的高度之差成为该结点的平衡因子。
只要能随时保证每个结点平衡因子的绝对值不超过1,AVL的高度就能始终保持O(logn)级别。
(1)存储结构
struct node{
int data;
int height; //当前子树高度
node *lchild;
node *rchild;
}
(2)创建新结点
node* newNode(int x){
node *root=new node;
root->lchild=NULL;
root->rchild=NULL;
root->data=x;
root->height=1;
return root;
}
(3)获取以root为根结点的子树的高度
int getHeight(node *root){
if(root==NULL)
return 0;
return root->height;
}
(4)计算结点root的平衡因子
int getBalanceFactor(node *root){
return getHeight(root->lchild)-getHeight(root->rchild);
}
(5)更新结点的高度(高度是从下往上计算)
void updateHeight(node *root){
root->height=max(getHeight(root->lchild),getHeight(root->rchild))+1;
}
2.平衡二叉树的操作
(1)查找
由于AVL树是一颗二叉查找树,所以查找操作和二叉查找树一摸一样。
void search(node *root,int x){
if(root==NULL){
printf("failed.\n");
return;
}
if(root->data==x)
printf("%d\n",root->data);
else if(x<root->data)
search(root->lchild,x);
else
search(root->rchild,x);
}
(2)旋转
1.左旋
假设有如下一颗AVL树,根结点为A,使其右子结点B为新的根结点,并保证调整后的树仍然是一颗AVL树,这个过程叫做左旋。
调整过程:使B的左子树成为A的右子树,A成为B的左子树,再将B设为根结点。
代码:
void L(node* &root){
node *t=root->rchild; //结点B
root->rchild=t->lchild;
t->lchild=root;
updateHeight(root); //更新A、B结点的高度
updateHeight(t);
root=t;
}
2.右旋
相应的与左旋对应的过程称为右旋。
代码:
void R(node* &root){
node *t=root->lchild;
root->lchild=t->rchild;
t->rchild=root;
updateHeight(root);
updateHeight(t);
root=t;
}
(3)插入
往一颗AVL树中插入一个结点时,一定会有结点的平衡因子发生变化(变为2或者-2),这样以改结点为根结点的子树就会失衡,需要进行调整。只有从根结点到该插入结点的路径上的结点才可能出现平衡因子变化,可以证明:只要把最靠近插入结点的失衡结点调整正常,路径上的所有结点都会平衡。
假定最靠近插入结点的失衡结点为A,它的平衡因子是2或-2,以A为根结点的子树有以下几种情况:
1.LL型
A的左孩子的平衡因子为1时为LL型。
调整过程:将C为根结点的子树看成是一个结点,再以A为根结点右旋就可以平衡。
2.LR型
A的左孩子的平衡因子为-1时为LR型。
调整过程:先以C为根结点左旋将情况转化为LL型,再以A为根结点右旋。
3.与上面两种对称的还有RR型(结点A的右孩子的平衡因子为-1)和RL型(结点A的右孩子的平衡因子为1),结点A平衡因子为-2,调整情况与上述两种情况也是对应的。
树型 | 条件 | 调整方法 |
---|---|---|
LL | BF(root)=2,BF(root->lchild)=1 | 将root右旋 |
LR | BF(root)=2,BF(root->lchild)=-1 | 将root->lchild左旋,再将root右旋 |
RR | BF(root)=-2,BF(root->lchild)=-1 | 将root左旋 |
RL | BF(root)=-2,BF(root->lchild)=1 | 将root->rchild右旋,再将root左旋 |
插入操作代码:
void insert(node* &root,int data){
if(root==NULL){
root=newNode(data);
return;
}
if(data<root->data){
insert(root->lchild,data);
updateHeight(root);
if(getBalancedFactor(root)==2){
if(getBalancedFactor(root->lchild)==1)
R(root);
else if(getBalancedFactor(root->lchild)==-1){
L(root->lchild);
R(root);
}
}
}
else{
insert(root->rchild,data);
updateHeight(root);
if(getBalancedFactor(root)==-2){
if(getBalancedFactor(root->rchild)==-1)
L(root);
else if(getBanlancedFactor(root->rchild)==1){
R(root->rchild);
L(root);
}
}
}
}
(4)AVL树的创建
node *Create(int data[],int n){
node *root=NULL;
for(int i=0;i<n;i++){
insert(root,data[i]);
}
return root;
}