平衡二叉樹(AVL樹)

來來來,今天我們來看看平衡二叉樹(又叫AVL樹)


平衡二叉樹是二叉排序樹的一個進化體,也是第一個引入平衡概念的二叉樹。因爲它的“平衡”,所以是一個很優秀的數據存儲結構。此數據結構插入、查找和刪除的時間複雜度均爲O(logN),但是插入和刪除需要額外的旋轉算法需要的時間,有時旋轉過多也會影響效率。

平衡二叉樹實現的大部分過程和二叉查找樹是一樣的(學平衡二叉樹之前一定要會二叉排序樹),區別就在於插入和刪除之後要寫一個旋轉算法去維持平衡,維持平衡需要藉助一個節點高度的屬性。

平衡二叉樹且具有以下性質:它是一 棵空樹或它的左右兩個子樹的高度差的絕對值不超過1,並且左右兩個子樹都是一棵平衡二叉樹。

由此概念,我們可以定義它的結構了。


//定義平衡二叉樹的結構
typedef struct BNODE
{
int data;         //數據
int bf;             //判斷子樹間的高度差
struct BNODE *lchild, *rchild;//左子樹和右子樹
}BNODE,*BTree;



因爲插入數據可能會導致二叉樹的的高度增高,進而不平衡了,所以我們就要通過旋轉來維持平衡


//對二叉樹的右旋操作
void RRotate(BTree *p)
{
BTree L;
L = (*p)->lchild;//L指向P的左子樹根結點
(*p)->lchild = L->rchild;//L的右子樹掛接爲p的左子樹
L->rchild = (*p);
*p = L;//p指向新的根節點
}


//對二叉樹的左旋操作
void LRotate(BTree *p)
{
BTree L;
L = (*p)->rchild;
(*p)->rchild = L->lchild;
L->lchild = (*p);
(*p) = L;
}


//左平衡旋轉

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


void LeftBalance(BTree *T)
{
BTree L, Lr;
L = (*T)->lchild;//L指向T的左子樹根節點

switch (L->bf)//檢查T的左子樹的平衡度,並作相應平衡處理
{
case LH://新節點插在T的左孩子的左子樹上,要作右旋處理
(*T)->bf = L->bf = EH;
RRotate(T);
break;


case  RH://新節點插在T的左孩子的右子樹上,要作雙旋處理
Lr = L->rchild;//Lr指向T的左孩子的右子樹根
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;
LRotate(&(*T)->lchild);//對T的左子樹作左旋平衡處理
RRotate(T);//對T作右旋平衡處理
}


}



//插入操作

bool Insert(BTree *T, int e, bool *t)//t反應樹T長高與否,ture爲長高,false不長高
{
if (!*T)//插入新節點,樹長高
{
*T = (BTree)malloc(sizeof(BNODE));
(*T)->data = e;
(*T)->lchild = (*T)->rchild = NULL;
(*T)->bf = EH;
*t = true;
}
else
{
if (e == (*T)->data)//樹中已經存在相同的數據就不再插入
{
*t = false;
return false;
}
if ((*T)->data > e)//在T的左子樹中繼續尋找
{
if (!Insert(&(*T)->lchild, e, t))//未插入
return false;
if (*t)//已插入到T的左子樹中且左子樹已經長高了
switch ((*T)->bf)//檢查T的平衡度
{
case LH://左子樹比右子樹高,需要左平衡處理
LeftBalance(T);
*t = true;
break;
case EH://原本左右子樹等高,現在因爲左子樹增高而樹也增高了
(*T)->bf = LH;
*t = true;
break;
case RH://原本右子樹比左子樹高,現在左右子樹等高
(*T)->bf = EH;
*t = false;
break;
}
}
else
{
if (!Insert(&(*T)->rchild, e, t))//未插入
return false;
if (*t)//已插入到T的右子樹中且右子樹已經長高了
switch ((*T)->bf)//檢查T的平衡度
{
case LH://左子樹比右子樹高,現在左右子樹等高
(*T)->bf = EH;
*t = false;
break;
case EH://原本左右子樹等高,現在因爲右子樹增高而樹也增高了
(*T)->bf = LH;
*t = true;
break;
case RH://原本右子樹比左子樹高,需要又平衡處理
RightBalance(T);
*t = false;
break;
}
}


}




return true;


}





發佈了29 篇原創文章 · 獲贊 9 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章