數據結構系列,二叉平衡樹的構建

平衡二叉樹

平衡二叉樹,首先要是一種二叉排序樹,

然後,其中每一個結點的左子樹,右子樹的高度差(左子樹的高度 – 右子樹的高度)至多等於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}

  1. 插入前兩個結點3,2時都是正常的構建,當插入第三個數1的時候,發現根結點3的BF變成了2,如圖1,此時整棵樹就是最小不平衡子樹,因爲BF爲正,將其右旋,如圖2。繼續插入結點4。

     

  2. 增加結點5時,結點3的BF變爲-2,如圖4,說明要左旋了,如圖5.

     

  3. 增加結點6時,結點2的BF變爲-2,如圖6,所以要左旋,如圖7,
  4. 增加結點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按中序遍歷的輸出結果,是一致的。

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