平衡二叉树:是一种二叉排序树,树中的每一个结点都满足,其左子树的深度与右子树深度的差值的最对值小于1.
平衡因子(Balanec factor):结点的左子树深度与右子树深度的差值,显然平衡二叉树中每个结点的平衡因子的值只能为-1,0 , 1.
最小不平衡子树:距离插入结点最近的,且平衡因子大于1的子树的根结点。
AVL树的建立:其实是按照二叉排序树的规则对树逐个插入结点,由于结点插入后,各结点的平衡因子会发生变化,可从底往上通过判断当前结点BF的值,来找到最小不平衡树,然后做出对应的操作,使之满足AVL树。
左旋与右旋操作示意图
新的结点的插入会导致原AVL的平衡被打破,共有两大类:(1)外部插入:最小不平衡树根结点与孩子结点的bf的符号相同(左左,右右),(2)内部插入:最小不平衡树的根结点与孩子结点的bf符号不相同(左右,右左)。对于情况(1),只需要但旋转后便能恢复平衡,而情况(2)则需要双旋转才能恢复平衡。
以下给出最小不平衡子树类型示意图:
代码
#include<stdio.h>
#include<stdlib.h>
#define LH 1//左高
#define EH 0//等高
#define RH -1//右高
#define SUCCESS 1
#define FAIL 0
typedef int status;
typedef struct avltnode//定义AVL树结点结构体,及结点指针类型
{
int data;
struct avltnode *lchild,*rchild;
int bf;
}avltnode,* avlptr;
void L_Rotate(avlptr *T)//左旋操作
{
avlptr r;
r = (*T)->rchild;//指向右孩子结点
(*T)->rchild = r->lchild;//右孩子结点的左子树挂接为原根结点的右子树
r->lchild = (*T);//指向新的根结点
*T = r;//指向新的根结点
}
void R_Rotate(avlptr *T)//右旋操作
{
avlptr l;
l = (*T)->lchild;//指向左孩子结点
(*T)->lchild = l->rchild;//左孩子结点的右子树挂接为原根结点的左子树
l->rchild = (*T);
*T = l;//指向新的根结点
}
/*在根结点的左子树插入时,当且仅当在左孩子结点的左子树插入时,根结点的bf和左孩子结点的bf是符号相同的
这样的最小不平衡树共三种情况,可通过右旋后恢复平衡,且都满足(*T)->bf = l->bf =EH;
而在左孩子的右子树插入时,根结点的bf和左孩子结点的bf符号时不相同的,因此需要先左旋左孩子使得符号相同
再通过右旋恢复平衡,对应的最小不平衡子树也有三种情况
同理可得右子树中的插入情况*/
void leftbalance(avlptr *T)//调整左子树的平衡因子及对应的连接关系
{
avlptr l,lr;
l = (*T)->lchild;
switch (l->bf)
{
case LH://外部插入 左左 左右
(*T)->bf = l->bf =EH;
R_Rotate(T);
break;
case RH://内部插入 右左 右右
lr = l->rchild;
switch(lr->bf)
{
case EH://lr为叶子结点
(*T)->bf = l->bf = EH;
break;
case LH://
lr->bf = EH;
(*T)->bf = RH;
l->bf = EH;
break;
case RH:
l->bf =LH;
lr->bf =EH;
(*T)->bf = EH;
break;
}
L_Rotate(&(*T)->lchild);//左旋左孩子结点
R_Rotate(T);//右旋操作
}
}
void rightbalance(avlptr *T)
{
avlptr r,rl;
r = (*T)->rchild;
switch (r->bf)
{
case RH:
(*T)->bf = r->bf = EH;
L_Rotate(T);
break;
case LH:
rl = r->lchild;
switch (rl->bf)
{
case EH:
(*T)->bf = r->bf = EH;//插入点的bf没有变化
break;
case LH:
(*T)->bf =EH;
rl->bf =EH;
r->bf = RH;
break;
case RH:
rl->bf = EH;
(*T)->bf =LH;
break;
}
R_Rotate(&(*T)->rchild);//右旋操作
L_Rotate(T);//左旋
}
}
status InsertAvltnode(avlptr *T,int e,int * taller)//平衡二叉排序树插入结点
{
avlptr l,r;
//*T 为根结点地址、e为需要插入的元素、*taller为布尔变量,用于判断子树是否长高了
if((*T)==NULL)//找到对应的位置进行插入
{
*T = (avlptr)malloc(sizeof(avltnode));
(*T)->data = e;
(*T)->lchild = NULL;
(*T)->rchild = NULL;
(*T)->bf = 0;
*taller = 1;//增高了
return SUCCESS;//插入成功
}
else
{
if (e==(*T)->data)//AVL树中含有这个值,不插入
{
*taller = 0;
return FAIL;
}
else if(e<(*T)->data)
{
if(InsertAvltnode(&(*T)->lchild,e,taller)==0)//继续遍历左子树,进行查找
{
return FAIL;//没有插入,返回
}
if((*taller)==1)//左子树中插入成功
{
switch ((*T)->bf)//从该叶子结点网上
{
case EH:
(*T)->bf = LH;
*taller = 1;
break;
case LH://
leftbalance(T);//平衡左子树
*taller = 0;
break;
case RH:
(*T)->bf = EH;
*taller = 0;
break;
}
}
}
else if(e>(*T)->data)
{
if(InsertAvltnode(&(*T)->rchild,e,taller)==0)//继续遍历右子树,进行查找
{
return FAIL;//没有插入,返回
}
if((*taller)==1)//右子树中插入成功
{
switch ((*T)->bf)//从该叶子结点往上找到最小不平衡子树
{
case EH:
(*T)->bf = RH;
*taller = 1;
break;
case LH://
(*T)->bf = EH;
*taller = 0;
break;
case RH:
rightbalance(T);//平衡左子树
*taller = 0;
break;
}
}
}
return SUCCESS;
}
}
void InorderTranverse(avlptr T)//中序遍历二叉树
{
if (T==NULL)
{
return;
}
else
{
InorderTranverse(T->lchild);
printf("%d\n",T->data);
InorderTranverse(T->rchild);
}
}
status Avl_Search(avlptr T,int e,avlptr * add,int *count)//avl树查找
{
(*count)++;
if (T==NULL)//没有找到
{
return FAIL;
}
else
{
if(e==T->data)
{
*add = T;//返回对应地址
return SUCCESS;
}
else if(e<T->data)
{
Avl_Search(T->lchild,e,add,count);
}
else
Avl_Search(T->rchild,e,add,count);
}
}
void main()
{
avlptr AvlT =NULL;
int taller =0;
//int a[]={1,2,3,4,5,6,7,8,9,10};
int a[]={6,2,1,3,4,10,7,8,5,9};
int i;//循环记录
int count[10]={0};//记录查找对应a[i]所用的次数
avlptr add = NULL;
//建立avl树
for (i=0;i<10;i++)
{
InsertAvltnode(&AvlT,a[i],&taller);
}
InorderTranverse(AvlT);
for (i=0;i<10;i++)
{
if(Avl_Search(AvlT,a[i],&add,&count[i]))//avl树查找
{
printf("%p,%3d,%3d\n",add,a[i],count[i]);
}
}
getchar();
}
运行结果: