二叉树上结点的左子树深度减去右子树深度的值称为平衡因子BF(balance factor)。
平衡二叉树上所有结点的BF只可能是-1、0、+1.
关键看BF。BF为负且小于-11即等于-2时,左旋;BF为正且大于1即等于2时,右旋。旋转后需要满足二叉排序树的特性,因此有些结点相对位置也会变。直接旋转的前提是最小不平衡子树的根节点与它的子节点的BF符号相同。 若不能直接旋转,则先统一BF符号。
实现构建平衡二叉树时,首先要改进二叉排序树的结点结构,增加bf域。
void R_Rotate(BiTree *P){
BiTree L;
L = (*P)->lchild;
(*P)->lchild = L->rchild; //L的右孩子大于L且小于P(P是L的父亲)
L->rchild = (*P);
*P = L;
}
//左旋类似
#define LH 1 //左高
#define EH 0 //等高
#define RH -1 //右高
/* 对以指针T所指结点为根的二叉树作左平衡旋转处理
算法结束时指针T指向新的根结点 */
void LeftBalance(BiTree *T){
//调用本函数时已经确认当前子树是不平衡状态,且左子树的高度大于右子树的高度。即此时T的根节点应该是BF大于1的数。
BiTre L,Lr;
L = (*T)->lchild;
switch(L->bf){
//检查T的左子树的平衡度
case LH: //新插入的结点插入在T的左孩子的左子树上,要做单右旋处理
// 表明与根节点的BF同号,因此都改成0.
(*T)->bf = L->bf = EH;
R_Rotate(T);
break;
case RH: //新结点插入在T的左孩子的右子树上,要做双旋处理
// 表明与根节点的BF异号。
Lr = L->rchild; //对根节点的不平衡的左孩子的不平衡的右孩子进行平衡处理
switch(Lr->bf){
case LH:
(*T)->bf = RH;
L->bf = EH;
break;
case EH:
(*T)->bf = L->bf = EH;
break;
case RH:
(*T)->bf = EH;
L->bf = LH;
break;
}
Lr->bf = EH;
L_Rotate(&(*T)->lchild); //对T的左子树做左旋平衡处理
R_Rotate(T); //对T做右旋平衡处理
}
}右平衡旋转处理函数类似。
主函数:
/* 若在平衡的二叉排序树T中不存在和e有相同关键字的结点,则插入一个数据元素为e的新结点并返回1,否则返回0.
若因插入而使二叉排序树失去平衡,则做平衡旋转处理,布尔变量taller反映T长高与否。 */
Status InsertAVL(BiTree *T, int e, Status *taller){
if(! *T){//当前T为空时,申请内存新增一个结点
//插入,树长高
*T = (BiTree)malloc(sizeof(BiTNode));
(*T)->data = e;
(*T)->lchild = (*T)->rchild = NULL;
(*T)->bf = EH;
*taller = TRUE;
}
else{
if(e == (*T)->data){
//树中已经存在和e有相同关键字的结点则不再插入
*taller = FALSE;
return FALSE;
}
if(e < (*T)->data){
//应继续在T的左子树中搜索
if(!InsertAVL(&(*T)->lchild,e,taller)){
return FALSE;
}
if(taller){
//已插入到T的左子树中且左子树长高
switch((*T)->bf){
//检查T的平衡度
case LH:
LeftBalance(T);
*taller = FALSE;
break;
case EH:
//没有失衡
(*T)->bf = LH;
*taller = TRUE:
break;
}
}
}
else{
//在右子树中继续搜索
//类似左子树。
}
}
return TRUE;
}

