平衡二叉樹的C語言實現(創建、插入、查找、刪除、旋轉)【數據結構】

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章