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;
}
}
}
}
}