1. 程式人生 > >數據結構 平衡二叉樹avl c++

數據結構 平衡二叉樹avl c++

歸納 all AI 例子 大於 樹節點 fin 深度 UC

平衡二叉樹:一顆空樹,或者是具有以下性質的二叉樹

  • 左子樹和右子樹都是平衡二叉樹
  • 左子樹和右子樹的深度只差不超過1

把二叉樹節點的平衡因子BF(Balance Factor)定義為該節點的左子樹深度減去右子樹深度,則平衡二叉樹所有結點的平衡因子只能是-1,0,1。只要有一個結點的平衡因子絕對值大於一就是不平衡的;

平衡二叉樹的構造

對二叉樹結點做一下定義,bf用來記錄結點的平衡因子

1 typedef struct BSTNode{
2     int val;
3     int bf;
4     struct BSTNode *lchild, *rchild;
5 }BSTNode, *BSTree;

在插入新結點的過程中,會出現平衡因子絕對值大於2的情況,這時就需要進行一定的條件,讓二叉樹保持平衡。失去平衡後進行的調整規律可以歸納為以下四種

  1. 單項右旋處理
  2. 單項左旋處理
  3. 雙向(先左後右)旋轉處理
  4. 雙向(先右後左)旋轉處理

單項右旋處理, p為失去平衡的結點。右旋的思路就是

1 void R_Roate(BSTree& p){
2     BSTree temp = p->lchild;
3     p->lchild = temp->rchild;
4     temp->rchild = p;
5     p = temp;
6 }

向二叉樹中插入結點:先找到結點插入的位置,建立該結點。調整相關結點的平衡因子。若導致結點失去平衡則需要進行選擇,讓二叉樹恢復平衡。 如何找到新結點插入位置? 如果val的值比當前結點的值小,則繼續在當前結點的左子樹中尋找插入位置。 如果val的值比當前結點的值大,則繼續在當前結點的右子樹中尋找插入位置。直到找到一個空的位置位置。當然如果發現存在相同的val,則表示已經存在於二叉樹中, 插入失敗;  那麽又如何判斷二叉樹是否失去平衡呢? 當當前結點的平衡因子是0的時候,表示該節點左右兩邊的高度一致,插入一個結點並不會改變當前結點的平衡性,但是會改變當前結點的平衡因子; 當當前結點的平衡因子為1的時候,表示當前節點的左子樹比右子樹高, 若在當前結點左邊插入結點, 必定會導致當前結點的左子樹高度和右子樹高度相差大於2. 引起不平衡。需要進行旋轉來讓二叉樹恢復平衡, 如果在右子樹插入結點,又會讓當前結點的的平衡因子變為0;平衡因子為-1的分析過程和前面類似。 參數taller用來標誌插入新結點是否讓二叉樹高度增加, 可以減少程序的計算量

 1 bool InsertAVL(BSTree& T, int val, bool& taller){
 2     if(!T){//插入新結點,樹變高
 3         T = (BSTree) malloc(sizeof(BSTNode));
 4         T->val = val; T->bf = EH; T->lchild = T->rchild = NULL;
 5         taller = true;
 6     }else{
 7         if(val==T->val){taller = false
; return false;} //如果val存在於二叉樹中, 則插入失敗 8 if(val<T->val){ //若果val比當前結點的值小,則把新結點插入到當前結點的左子樹中 9 if(!InsertAVL(T->lchild, val, taller)) return false; 10 if(taller){ 11 switch(T->bf){ //插入新結點後要對當前結點的平衡因子做出相應的修改 12 case LH:{LeftBalance(T); taller=false; break;} 13 case EH:{taller = true; T->bf = LH; break;} 14 case RH:{taller = false; T->bf = EH; break;} 15 }} 16 }else{ 17 if(!InsertAVL(T->rchild, val, taller)) return false; 18 if(taller){ 19 switch(T->bf){ 20 case LH:{T->bf = EH; taller = false; break;} 21 case EH:{T->bf = RH; taller = true; break;} 22 case RH:{RightBalance(T); taller = false; break;} 23 }} 24 } 25 } 26 return true; 27 }

全部代碼

  1 #include<iostream>
  2 using namespace std;
  3 /*
  4     author: Lai XingYu
  5       date: 2018/5/18
  6   describe: AVL
  7 */
  8 #define LH +1
  9 #define EH 0
 10 #define RH -1
 11 
 12 typedef struct BSTNode{
 13     int val;
 14     int bf;
 15     struct BSTNode *lchild, *rchild;
 16 }BSTNode, *BSTree;
 17 
 18 void R_Roate(BSTree& p){
 19     BSTree temp = p->lchild;
 20     p->lchild = temp->rchild;
 21     temp->rchild = p;
 22     p = temp;
 23 }
 24 
 25 void L_Roate(BSTree& p){
 26     BSTree temp = p->rchild;
 27     p->rchild = temp->lchild;
 28     temp->lchild = p;
 29     p = temp;
 30 }
 31 
 32 void LeftBalance(BSTree& T){
 33     BSTree temp = T->lchild;
 34     switch(temp->bf){
 35     case LH:{T->bf = temp->bf = EH; R_Roate(T); break;}
 36     case RH:{
 37                 BSTree t = temp->rchild;
 38                 switch(t->bf){
 39                 case LH:{temp->bf = EH; T->bf = RH; break;}
 40                 case EH:{temp->bf = EH; T->bf = EH; break;}
 41                 case RH:{temp->bf = LH; T->bf = EH; break;}
 42                 }
 43                 t->bf = EH;
 44                 L_Roate(T->lchild);
 45                 R_Roate(T);
 46             }
 47     }
 48 }
 49 
 50 void RightBalance(BSTree& T){
 51     BSTree temp = T->rchild;
 52     switch(temp->bf){
 53     case LH:{
 54                 BSTree t = temp->lchild;
 55                 switch(t->bf){
 56                 case LH:{T->bf = EH; temp->bf = RH; break;}
 57                 case EH:{T->bf = EH; temp->bf = EH; break;}
 58                 case RH:{T->bf = LH; temp->bf = EH; break;}
 59                 }
 60                 t->bf = EH;
 61                 R_Roate(T->rchild);
 62                 L_Roate(T);
 63             }
 64     case RH:{T->bf = temp->bf = EH; L_Roate(T); break;}
 65     }
 66 }
 67 
 68 /*
 69     taller標誌插入新結點後,樹的高度是否變高
 70     如果val在二叉樹中,則插入失敗
 71     如果插入結點讓二叉樹失去平衡,則要進行選擇處理,讓二叉樹恢復平衡
 72 */
 73 bool InsertAVL(BSTree& T, int val, bool& taller){
 74     if(!T){//插入新結點,樹變高
 75         T = (BSTree) malloc(sizeof(BSTNode));
 76         T->val = val; T->bf = EH; T->lchild = T->rchild = NULL;
 77         taller = true;
 78     }else{
 79         if(val==T->val){taller = false; return false;} //如果val存在於二叉樹中, 則插入失敗
 80         if(val<T->val){ //若果val比當前結點的值小,則把新結點插入到當前結點的左子樹中
 81             if(!InsertAVL(T->lchild, val, taller)) return false;
 82             if(taller){
 83             switch(T->bf){    //插入新結點後要對當前結點的平衡因子做出相應的修改
 84             case LH:{LeftBalance(T); taller=false; break;}
 85             case EH:{taller = true; T->bf = LH; break;}
 86             case RH:{taller = false; T->bf = EH; break;}
 87             }}
 88         }else{
 89             if(!InsertAVL(T->rchild, val, taller)) return false;
 90             if(taller){
 91             switch(T->bf){
 92             case LH:{T->bf = EH; taller = false; break;}
 93             case EH:{T->bf = RH; taller = true; break;}
 94             case RH:{RightBalance(T); taller = false; break;}
 95             }}
 96         }
 97     }
 98     return true;
 99 }
100 
101 void inorder(BSTree T){
102     if(!T) return;
103     if(T->lchild) inorder(T->lchild);
104     cout<<T->val<<" ";
105     if(T->rchild) inorder(T->rchild);
106 }
107 int main(){
108     int t[] = {1,2,3,4,5,6,7};
109     int f[] = {1,2,5,3,7,6,4};
110     BSTree T = NULL;
111     bool taller;
112     for(int i=0; i<7; i++) InsertAVL(T, f[i], taller);
113     inorder(T);
114 return 0;}

inorder()遍歷一顆二叉樹,得到的序列一定是單調的。

通過上面的例子可以看到,用相同的數字,不同順序的序列來構建平衡二叉樹,得到的結果是一樣的。

平衡二叉樹可以讓二叉樹的高度保持在Logn; 查找任何一個結點,需要進行的比較次數也不會超過logn。

但是如果構建avl的結點是降序的,會對二叉樹進行多次選擇,帶來的開銷也是非常大的。

數據結構 平衡二叉樹avl c++