平衡二叉樹(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;
}