26. 平衡二叉排序樹

  對於給定的數組,如果按照之前的方式進行排序的話,有的時候會得到如下的結果

在其中查找數字 5 ,很幸運只需要兩步比較就可以得到最後的結果。但是也有可能變爲如下的這種情況

如果這個時候我們是要查找 9 的話就需要一直找到最後,所以這種情況是不好的。爲了避免這種效率極端低下的查找過程,可以使用平衡二叉樹排序樹這種數據結構

1. 相關定義

  平衡二叉排序樹要求每個節點的左右子樹有着相同高度,或者要求任何節點的左右節點的左右子樹高度差不超過1。

  根據定義我們可以判斷以下的幾棵樹是否屬於平衡二叉排序樹

  上面這個滿足定義的要求,是一棵平衡二叉排序樹。

  這棵樹看起來像是平衡二叉排序樹,因爲他的深度滿足要求;但實際上它並不是,因爲首先不是一棵二叉排序樹。

  這個也不是平衡二叉排序樹,因爲它雖然滿足了二叉排序樹的要求,但是並沒有達到平衡的要求。比如說結點 9 的左子樹的深度要比右子樹的深度大 2,這就超過 1 了。

  這是平衡二叉排序樹。

2. 實現原理

  對於一個給定的數組 [3, 2, 1, 4, 5, 6, 7, 10, 9, 8],如果不適用平衡二叉排序樹的生成方法,很有可能得到如下的結果

這個結果明顯是查找效率極低的,所以使用如下的平衡二叉排序樹的方法。前三個數字組成的數組如下圖所示

明顯這已經是一個不平衡的二叉排序樹,我們可以看到左子樹的深度減去右子樹的深度都是大於零的,所以樹向右旋轉得到如下圖所示的結果

  之後再加上 4 5 兩個元素可以得到如下的圖像

我們可以看到這個二叉排序樹中,對於 2 3 兩個結點都是不平衡的,且兩者的不平衡因子都是 2 ,在這裏是 3 的不平衡導致了 2 不平衡,所以調整 3 4 5 這棵不平衡術就可以了,因爲在這兩個不平衡點中不平衡因子(BF)都是負數,所以應該將這棵最小不平衡樹進行左旋轉,如下圖所示

  再向其中加入 6 這個結點,如下圖所示

在這棵樹中可以看到只有根節點 2 是不平衡的,且 BF = -2 < 0,所以需要將根節點 2 向左旋轉,得到如下的結果

這個時候可以看到樹已經不是一個二叉樹,所以需要對 3 進行處理,由於 3 小於 4 ,所以將 3 連接在 4 的左子樹的最右端,得到如下圖所示的結果

  然後向其中加入數據節點 7 ,得到如下的結果

其中的 5 6 7 構成了最小不平衡樹,將它進行左旋轉,得到如下結果

  再向其中加入 10 9 兩個點,可以發現對於4 6 7 三個結點,它們的 bf = 2 ,所以需要調整二叉排序樹,如下圖所示

但是這個結點不可以像之前一樣通過旋轉 7 10 9 這棵子樹,因爲這個時候, 10 結點的 BF 符號與之前的符號均不相同,所以要首先將 9 10 旋轉,之後再將不平衡子樹進行旋轉,如下圖所示
這裏寫圖片描述

其中左側是將 9 10 旋轉之後得到的結果,而右側是再經過一層旋轉得到二叉平衡樹。

  最後向樹中添加結點 8,得到的結果如下圖所示

明顯結點 4 的 BF 爲正,結點 6 的 BF 爲正,但是結點 9 的 BF 爲負,這個時候應該先將 8 7 9 10 進行旋轉,使得 BF 值相等,然後再調整二叉排序樹,如下圖所示

這裏寫圖片描述

經過第一次旋轉之後得到的結果如上圖中左圖所示,明顯 4 6 結點不平衡,所以對 6 結點進行左旋轉,得到上圖中中間的圖,這個時候的樹不是二叉樹,所以需要對 8 進行處理,因爲 8 的值比對應的根節點 7 大,所以將它放在根節點 7 右子樹的最左側,得到上圖中右圖所示的情況,至此完成了平衡二叉樹的生成。

3. 代碼

#define LH 1
#define EH 0
#define RH -1

typedef struct BiTNode
{
    int data;
    int bf;
    struct BiTNode *lchild, *rchild;
} BiTNode, *BiTree;

void R_Rotate(BiTree *p)
{
    BiTree L;
    L = (*p)->lchild;
    (*p)->lchild = L->rchild;
    L->rchild = (*p);
    *p = L;

}

void LeftBalance(BiTree *T)
{
    BiTree L, Lr;
    L = (*T)->lchild;

    switch(L->bf)
    {
        case LH:
            (*T)->bf = L->bf = EH;
            R_Rotate(T);
            break;
        case RH:
            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);
            R_Rotate(T);
    }
}

int InsertAVL(BiTree *T, int e, int *taller)
{
    if( !*T )
    {
        *T = (BiTree)malloc(sizeof(BiTNode));
        (*T)->data = e;
        (*T)->lchild = (*T)->rchild = NULL;
        (*T)->bf = EH;
        *taller = TRUE;
    }
    else
    {
        if(e == (*T)->data)
        {
            *taller = FALSE;
            return FALSE;
        }
        if(e < (*T)->data)
        {
            if(!InsertAVL(&(*T)->lchild, e, taller))
            {
                return FALSE;
            }
            if(*taller)
            {
                switch((*T)->bf)
                {
                    case LH:
                        LeftBalance(T);
                        *taller = FALSE;
                        break;
                    case EH:
                        (*T)->bf = LH;
                        *taller = TRUE;
                        break;
                    case RH:
                        (*T)->bf = EH;
                        *taller = FALSE;
                        break;
                }
            }
        }
        else
        {
            if(!InsertAVL(&(*T)->rchild, e, taller))
            {
                return FALSE;
            }
            if(*taller)
            {
                switch((*T)->bf)
                {
                    case LH:
                        (*T)->bf = EH;
                        *taller = FALSE;
                        break;
                    case EH:
                        (*T)->bf = RH;
                        *taller = TRUE;
                        break;
                    case RH:
                        RightBalance(T);
                        *taller = FALSE;
                        break;
                }
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章