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