平衡二叉树(AVL)或者是一颗空树,或者是具有下列性质的非空二叉搜索树:
(1). 任一结点的左、右子树均为AVL树;
(2). 任一结点的左、右子树高度差的绝对值不超过1。
对于二叉树中任一结点T,其“平衡因子”(Balance Factor, BF)定义为BF(T) = Hl-Hr,其中Hl和Hr分别为T的左、右子树的高度。
有了平衡因子的定义,AVL树“任一结点左右子树高度差的绝对值不超过1”这一性质可以表述为“一棵AVL树中任一结点的平衡因子只能在集合{-1,0,1}中取值”。这就是平衡的量化标准。
当一棵AVL树插入或删除一个结点时,该结点的平衡因子很可能不在上述集合范围内,破坏了树的平衡,这时就需要做“平衡化”处理,即相应的局部“旋转”调整,使得调整后的树达到平衡。
(1). 单旋调整(左左、右右)
(2). 双旋调整(左-右、右-左)
基本操作:
//=========================================================================================
// 平衡二叉树---AVL
//=========================================================================================
//Define an AVLTree
typedef struct AVLTreeNode *AVLTree;
typedef struct AVLTreeNode{
int Data;
AVLTree Left;
AVLTree Right;
int Height;
}
//=========================================================================================
//平衡二叉树的插入操作(按中序操作)
AVLTree AVL_Insertion(ElementType X, AVLTree T){//将X插入树T中,并返回调整后的树
if(!T){
T = malloc(sizeof(AVLTreeNode));
T->Data = X;
T->Height = 0;
T->Left = T->Right = NULL;
}
else if(X < T->Data){
T->Left = AVL_Insertion(X, T->Left); //递归比较并插入,将插入后的左子树更新给T-Left
if(GetHeight(T->Left) - GetHeight(T->Right) == 2)
if(X < T->Left->Data)
T = SingleLeftRotation(T); //左单旋
else
T = DoubleLeftRightRotation(T); //左-右双旋
}
else if(X > T->Data){
T->Right = AVL_Insertion(X, T->Right); //递归比较并插入,将插入后的右子树更新给T->Right
if(GetHeight(T->Left) - GetHeight(T->Right) == -2)
if(X > T->Right->Data)
T = SingleLeftRotation(T); //右单旋
else
T = DoubleRightLeftRotation(T); //右-左双旋
}
//else X == T->Data, 无需插入
T->Height = Max(GetHeight(T->Left), GetHeight(T->Right)) + 1;//树高等于子树高度加一
return T; //返回插入并调整后的树
}
//=========================================================================================
//左单旋算法
AVLTree SingleLeftRotation(AVLTree A){
//注意:A必须有一个左子结点B
//将A与B做左单旋,更新A与B的高度,返回新的根结点B
AVLTree B = A->Left;
A->Left = B->Right;
B->Right = A;
A->Height = Max(GetHeight(A->Left), GetHeight(A->Right)) + 1;
B->Height = Max(GetHeight(B->Left), GetHeight(A->Height)) + 1;
return B;
}
//=========================================================================================
//左-右双旋算法
AVLTree DoubleLeftRightRotation(AVLTree A){
//注意:A必须有一个左子结点B,且B必须有一个右子结点C
//将A.B与C做单旋两次,返回新的根结点C
A->Left = SingleRightRotation(A->Left);//将B与C做右单旋,C被返回
return SingleLeftRotation(A); //将A与C做左单旋,C被返回
}
//=========================================================================================
//平衡二叉树的查找操作
AVLTree Find(ElementType X, AVLTree T){
if(!T)
return NULL;
if(X < T->Data)
return Find(X, T->Left);
else if(X > T->Data)
return Find(X, T->Right);
else
return T;
}
//=========================================================================================
//平衡二叉树的删除操作
//删除方法与二叉查找树一致,区别是,删除完成后,需要从删除节点的父亲开始向上维护树的
//平衡一直到根结点(调整树)。
AVLTree Delete(ElementType X, AVLTree T){
if(!T){ //树为空,报错
printf("ERROR!");
return NULL;
}
if(X < T->Data)
T->Left = Delete(X, T->Left); //递归查找并删除指定元素X
else if(X > T->Data)
T->Right = Delete(X, T->Right);
else{
if(T->Left && T->Right){ //此结点含有左右两个子树
AVLTree Tmp = T->Right;
while(Tmp->Left != NULL) //查找T的右子树的最小值用于填补删除的元素的位置
Tmp = Tmp->Left;
T->Data = Tmp->Data;
T->Right = Delete(Tmp->Data, T->Right);//删除移位后的Tmp->Data
if(GetHeight(T->Left) - GetHeight(T->Right) == 2){
//将T看做根结点,删除的元素在右子树,此时判断左子树与右子树的高度差是不是>=2
//若是,则判断左子树是左单旋还是左-右双旋
//若T->Left的右子树比左子树长,则为左-右双旋
//若T->Left的左子树比右子树长,则为左单旋
// A
// / A为T, B为T->Left
// B 若C分支长(T->Left->Left),则为左单旋
// / \ 若D分支长(T->Left->Right),则为左右双旋
// C D
// : :
if((T->Left->Right != NULL) && GetHeight(T->Left->Right) > GetHeight(T->Left->Left))
DoubleLeftRightRotation(T); //调用左-右双旋算法
else
SingleLeftRotation(T); //调用左单旋算法
}
}else{ //此结点含有一个或零个子树
AVLTree Tmp = T;
if(!T->Left)
T = T->Right;
else if(!T->Right)
T = T->Left;
free(Tmp); //释放Tmp
}
}
T->Height = Max(GetHeight(T->Left), GetHeight(T->Right));
return T;
}