平衡二叉樹
平衡二叉樹,首先要是一種二叉排序樹,
然後,其中每一個結點的左子樹,右子樹的高度差(左子樹的高度 – 右子樹的高度)至多等於1,二叉樹的高度就是這棵樹有幾層。
將二叉樹上結點的左子樹深度減去右子樹深度的值稱爲平衡因子BF,所有結點的平衡因子的值,只可能是-1, 0, 1。只要二叉樹上有一個結點的平衡因子絕對值大於1,則該二叉樹就是不平衡的。
距離插入結點最近的,且平衡因子的絕對值大於1的結點爲跟的子樹,稱爲最小不平衡子樹。
當新插入結點37時,距離37這個結點最近的平衡因子絕對值超過1的結點是58,所以58就是最小不平衡子樹。
爲了構建平衡二叉樹,需要在構建時,每次插入結點,先要檢查是否因爲插入結點破壞了樹的平衡性,如果破壞了,就找出最小不平衡樹,進行旋轉,使之成爲新的不平衡子樹。
平衡二叉樹,就是在二叉排序樹的創建過程中保證他的平衡性,一旦插入結點出現不平衡,就馬上旋轉使其平衡。
當最小不平衡子樹根結點的平衡因子BF大於1時,做右旋;當BF小於-1時做左旋;
當最小不平衡子樹的BF與它的子樹的BF符號相反時,就要先對它的子樹進行一次旋轉使得符號相同後,在反向旋轉最小不平衡樹,完成平衡操作。
依據上面的二叉排序樹的插入,旋轉策略,來實現構建一棵平衡二叉樹。
現在有10個結點,
Int a[10] = {3, 2, 1, 4, 5, 6, 7, 10, 9, 8}
- 插入前兩個結點3,2時都是正常的構建,當插入第三個數1的時候,發現根結點3的BF變成了2,如圖1,此時整棵樹就是最小不平衡子樹,因爲BF爲正,將其右旋,如圖2。繼續插入結點4。
- 增加結點5時,結點3的BF變爲-2,如圖4,說明要左旋了,如圖5.
- 增加結點6時,結點2的BF變爲-2,如圖6,所以要左旋,如圖7,
- 增加結點7時,也要左旋,如圖8,圖9.
5,增加結點10,沒有變化,在增加結點9時,結點7的BF變爲-2,如圖11,如果直接左旋7,9,10,因爲結點9變成10的右孩子,不符合二叉排序樹的特性,所以不能簡單的左旋,前面我們說,如果最小不平衡子樹的BF跟他的子樹的BF符號不一致,要先選擇其子樹,使他們的BF符號統一,在反向旋轉最小不平衡子樹。
所以先要對9,10做右旋,在對7,9,10做左旋,如圖12,圖13,
6,在插入結點8,因爲6的BF變爲-2,它的右孩子9的BF變爲1,如圖14,所以要先對9右旋,如圖15,在對6左旋,如圖16.
代碼實現:
#ifndef DATA_STRUCTURE_BINARY_BF_TREE_CLASS_H #define DATA_STRUCTURE_BINARY_BF_TREE_CLASS_H #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define MAXSIZE 100 //存儲空間初始分配量 #define MAX_TREE_SIZE 100 //二叉樹最大結點樹 typedef int Status; //表示函數結果的狀態碼 typedef int TreeElemType; //樹節點的數據類型,暫定int typedef TreeElemType SqBiTree[MAX_TREE_SIZE]; //順序存儲結構數組 typedef struct BiTNode { int data;//結點的值 int bf;//平衡因子 struct BiTNode *lchild, *rchild;//左右孩子指針 }BiTNode, *BiTree; TreeElemType Nil = 0; //表示空元素 Status Delete(BiTree *p); void R_Rotate(BiTree *p); void L_Rotate(BiTree *p); #endif
#include "BinaryBFTree.h" #include "iostream" #include "cstdlib" #include "cmath" using namespace std; #define arrayLength(array) sizeof(array) / sizeof(array[0]) const int array[10]={3,2,1,4,5,6,7,10,9,8}; Status visit(BiTree T) { if (NULL != T) { cout << "value=" << T->data << endl; } else { cout << "T is null!" <<endl; } return OK; } void InOrderTraverseBST(BiTree T) { if (NULL == T) { //cout << "T is null!" <<endl; return; } else { InOrderTraverseBST(T->lchild); visit(T); InOrderTraverseBST(T->rchild); } } /* *對以P爲跟結點的二叉排序樹做右旋,旋轉後p爲新的根結點。 */ void R_Rotate(BiTree *p) { BiTree L; L = (*p)->lchild; //p的左孩子,爲新的根結點 (*p)->lchild = L->rchild; //p的左孩子的右孩子,爲p的左孩子 L->rchild = (*p);//新的根結點右孩子,爲原來的p *p = L;//指向新的根結點,原根結點的左孩子的左孩子指向沒有變。 } /* *對p爲根的二叉排序樹做左旋處理,旋轉後p爲新的根結點 */ void L_Rotate(BiTree *p) { BiTree R; R= (*p)->rchild; (*p)->rchild = R->lchild; R->lchild = (*p); *p = R; } //最小不平衡子樹的子樹的高度值。 #define LH +1 //左高 #define EH 0 //等高 #define RH -1 //右高 /* * 對T爲根結點的最小不平衡子樹做左平衡旋轉 */ void LeftBalance(BiTree *T) { BiTree L, Lr; L = (*T)->lchild; switch(L->bf) { //新插入結點在T的左孩子的左子樹上,做右旋 case LH: (*T)->bf = L->bf = EH; R_Rotate(T); break; //新插入結點在T的左孩子的右子樹上,做雙旋 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; //對T的左子樹做左旋 L_Rotate(&((*T)->lchild)); //對T做右旋 R_Rotate(T); } } /* *對T爲根結點的最小不平衡子樹作右平衡旋轉處理, */ void RightBalance(BiTree *T) { BiTree R, Rl; R = ( * T)->rchild; /* R指向T的右子樹根結點 */ switch (R -> bf) { /* 檢查T的右子樹的平衡度,並作相應平衡處理 */ case RH: /* 新結點插入在T的右孩子的右子樹上,要作單左旋處理 */ ( * T)->bf = R -> bf = EH; L_Rotate(T); break; case LH: /* 新結點插入在T的右孩子的左子樹上,要作雙旋處理 */ Rl = R -> lchild; /* Rl指向T的右孩子的左子樹根 */ switch (Rl -> bf) { /* 修改T及其右孩子的平衡因子 */ case RH: ( * T)->bf = LH; R -> bf = EH; break; case EH: ( * T)->bf = R -> bf = EH; break; case LH: ( * T)->bf = EH; R -> bf = RH; break; } Rl -> bf = EH; R_Rotate( & ( * T)->rchild); /* 對T的右子樹作右旋平衡處理 */ L_Rotate(T); /* 對T作左旋平衡處理 */ } } /* 若在平衡的二叉排序樹T中不存在和e有相同關鍵字的結點,則插入一個 * 數據元素爲e的新結點,並返回1,否則返回0。若因插入而使二叉排序樹 * 失去平衡,則作平衡旋轉處理,布爾變量taller反映T長高與否 */ Status InsertAVL(BiTree *T, int e, Status *taller) { if (! * T) { /* 插入新結點,樹“長高”,置taller爲TRUE */ *T = new BiTNode; ( * T)->data = e; ( * T)->lchild = ( * T)->rchild = NULL; ( * T)->bf = EH; *taller = TRUE; } else { if (e == ( * T)->data) { /* 樹中已存在和e有相同關鍵字的結點則不再插入 */ *taller = FALSE; return FALSE; } if (e < ( * T)->data) { /* 應繼續在T的左子樹中進行搜索 */ if (!InsertAVL( & ( * T)->lchild, e, taller)) /* 未插入 */ return FALSE; if (*taller) { /* 已插入到T的左子樹中且左子樹“長高” */ switch (( * T)->bf) {/* 檢查T的平衡度 */ case LH: /* 原本左子樹比右子樹高,需要作左平衡處理 */ LeftBalance(T); *taller = FALSE; break; case EH: /* 原本左、右子樹等高,現因左子樹增高而使樹增高 */ ( * T)->bf = LH; *taller = TRUE; break; case RH: /* 原本右子樹比左子樹高,現左、右子樹等高 */ ( * T)->bf = EH; *taller = FALSE; break; } } } else { /* 應繼續在T的右子樹中進行搜索 */ if (!InsertAVL( & ( * T)->rchild, e, taller)) /* 未插入 */ return FALSE; if (*taller) { /* 已插入到T的右子樹且右子樹“長高” */ switch (( * T)->bf) {/* 檢查T的平衡度 */ case LH: /* 原本左子樹比右子樹高,現左、右子樹等高 */ ( * T)->bf = EH; *taller = FALSE; break; case EH: /* 原本左、右子樹等高,現因右子樹增高而使樹增高 */ ( * T)->bf = RH; *taller = TRUE; break; case RH: /* 原本右子樹比左子樹高,需要作右平衡處理 */ RightBalance(T); *taller = FALSE; break; } } } } return TRUE; } int main() { BiTree T = NULL; Status taller; for(int i=0;i<arrayLength(array);i++) { InsertAVL(&T,array[i],&taller); } InOrderTraverseBST(T); }
/*output*/
/BinaryTree$ g++ -g BinaryBFTree.cpp -o BFTree /BinaryTree$ ./BFTree value=1 value=2 value=3 value=4 value=5 value=6 value=7 value=8 value=9 value=10
對圖16按中序遍歷的輸出結果,是一致的。