平衡二叉樹,是一個方便查找的樹,樹的左子樹深度與右子樹的深度的差總(BF)是在+1,0,-1之中。ide
隨着樹的創建,插入,樹都會自動的進行調整,使得其知足上面的條件。spa
一、+1表示左子樹的深度比右子樹的深度多1.指針
二、0 表示左子樹的深度與右子樹的深度相同。code
三、-1表示左子樹的深度比右子樹神的小1.blog
所以,若是一個數據插入到狀況1中,也就是說,數據插入到左子樹中,左子樹的深度將會比右子樹多2.此時,須要調整樹的結構。若是插入尾端節點的左子樹中,則這個尾端節點相應的BF值,就變成+1.相反,若是插入到它的右子樹中,BF值就會變成-1.這個調整也會返回到上面一層的節點,再次進行調整。get
這裏相應的介紹一個左旋,與右旋的基本知識。it
好比下圖io
在進行左旋時,將會發生下面的狀況:class
void L_Rotate(BiTree *p){ //傳入根節點進行右旋 BiTree R; R = (*p)->rchild; (*p)->rchild = R->lchild; R->lchild = (*p); (*p) = R; }
最後子樹將會變成二叉樹
相應的右旋,則運行下面的代碼
void R_Rotate(BiTree *p){ //傳入一個根節點,進行右旋。定義它的左子樹節點爲L,根節點的左子樹變成L的右子樹,L的右子樹變成根節點。最後把根節點指針指向L BiTree L; L = (*p)->lchild; (*p)->lchild = L->rchild; L->rchild = (*p); (*p) = L; }
瞭解左旋與右旋後,就該進行樹的調整介紹了。
這裏有一個技巧:
1 若是插入的元素插入到左子樹,使得左子樹的BF值發生改變。若是左子樹節點的BF值,與根節點的BF值相同符號,則進行一次右旋,便可。可是若是是不一樣符號,則要進行雙旋(即先進性左旋,使得子樹高度加一,在進行右旋,平衡子樹)
2 若是插入到右子樹,也觀察符號,相同,則進行一次右旋,若是不一樣,則進行雙旋。
代碼以下
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://符號與根不一樣,要進行雙旋;對子樹進行一次旋轉,再對T進行一次旋轉 Lr = L->rchild; switch(Lr->bf){ case LH: //若是是左子數高,那麼對根節點賦值爲-1,由於沒有右子樹,根節點將會出現左子樹爲空的狀況;左子樹旋轉後,會平衡爲EH (*T)->bf = RH; L->bf = EH; break; case EH://若是爲平衡,那麼根節點和左子樹節點都爲平衡EH (*T)->bf = L->bf = EH; break; case RH://若是右子樹高,那麼對根節點賦值爲0,對左子樹賦值爲+1,由於進行旋轉後,左子樹節點的右子樹會空。根節點EH (*T)->bf = EH; L->bf = LH; break; } Lr->bf = EH; L_Rotate(&(*T)->lchild); R_Rotate(T); } } void RightBalance(BiTree *T){ BiTree R,Rl; R = (*T)->rchild; switch(R->bf){ case RH: (*T)->bf = R->bf = EH; L_Rotate(T); break; case LH: Rl = R->lchild; switch(Rl->bf){ case LH: //若是是左子數高,那麼對根節點賦值爲-1,由於沒有右子樹,根節點將會出現左子樹爲空的狀況;左子樹旋轉後,會平衡爲EH (*T)->bf = EH; R->bf = RH; break; case EH://若是爲平衡,那麼根節點和左子樹節點都爲平衡EH (*T)->bf = R->bf = EH; break; case RH://若是右子樹高,那麼對根節點賦值爲0,對左子樹賦值爲+1,由於進行旋轉後,左子樹節點的右子樹會空。根節點EH (*T)->bf = LH; R->bf = EH; break; } Rl->bf = EH; R_Rotate(&(*T)->rchild); L_Rotate(T); } }
插入時,要遍歷到子樹的最底層,進行分析,逐層的改變BF值,進行平衡。知道標記taller爲0時,表示對深度不發生改變,就不須要向上遍歷了。
int insertAVL(BiTree *T,int e, int *taller){ if(!(*T)){ (*T)=(BiTree)malloc(sizeof(BiTNode)); (*T)->data = e; (*T)->lchild = NULL; (*T)->rchild = NULL; (*T)->bf = EH; *taller = 1; }else{ if(e == (*T)->data){ //存在相同節點 *taller = 0; return 0; } if(e < (*T)->data){ if(!insertAVL(&(*T)->lchild,e,taller)) return 0; if(taller){ switch((*T)->bf){ case LH: LeftBalance(T); *taller = 0; break; case EH: (*T)->bf = LH; *taller = 1; break; case RH: (*T)->bf = EH; *taller = 0; break; } } }else{ if(!insertAVL(&(*T)->rchild,e,taller)) return 0; if(taller){ switch((*T)->bf){ case LH: (*T)->bf = 0; *taller = 0; break; case EH: (*T)->bf=RH; *taller = 1; break; case RH: RightBalance(T); *taller = 0; break; } } } } return 1; }
#include <stdio.h> #include <stdlib.h> #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); void L_Rotate(BiTree *p); void LeftBalance(BiTree *p); void RightBalance(BiTree *T); int insertAVL(BiTree *T,int e, int *taller); void InOrderTree(BiTree b); int main(){ int i; int a[10]={4,7,9,1,2,3,0,5,6,8}; BiTree T = NULL; int *taller = (int *)malloc(sizeof(int)); for(i=0;i<10;i++){ insertAVL(&T,a[i],taller); InOrderTree(T); printf("\n"); } getchar(); } void InOrderTree(BiTree b){ if( b== NULL) return; InOrderTree(b->lchild); printf("%d ",b->data); InOrderTree(b->rchild); } int insertAVL(BiTree *T,int e, int *taller){ if(!(*T)){ (*T)=(BiTree)malloc(sizeof(BiTNode)); (*T)->data = e; (*T)->lchild = NULL; (*T)->rchild = NULL; (*T)->bf = EH; *taller = 1; }else{ if(e == (*T)->data){ //存在相同節點 *taller = 0; return 0; } if(e < (*T)->data){ if(!insertAVL(&(*T)->lchild,e,taller)) return 0; if(taller){ switch((*T)->bf){ case LH: LeftBalance(T); *taller = 0; break; case EH: (*T)->bf = LH; *taller = 1; break; case RH: (*T)->bf = EH; *taller = 0; break; } } }else{ if(!insertAVL(&(*T)->rchild,e,taller)) return 0; if(taller){ switch((*T)->bf){ case LH: (*T)->bf = 0; *taller = 0; break; case EH: (*T)->bf=RH; *taller = 1; break; case RH: RightBalance(T); *taller = 0; break; } } } } return 1; } void R_Rotate(BiTree *p){ //傳入一個根節點,進行右旋。定義它的左子樹節點爲L,根節點的左子樹變成L的右子樹,L的右子樹變成根節點。最後把根節點指針指向L BiTree L; L = (*p)->lchild; (*p)->lchild = L->rchild; L->rchild = (*p); (*p) = L; } void L_Rotate(BiTree *p){ //傳入根節點進行右旋 BiTree R; R = (*p)->rchild; (*p)->rchild = R->lchild; R->lchild = (*p); (*p) = R; } 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://符號與根不一樣,要進行雙旋;對子樹進行一次旋轉,再對T進行一次旋轉 Lr = L->rchild; switch(Lr->bf){ case LH: //若是是左子數高,那麼對根節點賦值爲-1,由於沒有右子樹,根節點將會出現左子樹爲空的狀況;左子樹旋轉後,會平衡爲EH (*T)->bf = RH; L->bf = EH; break; case EH://若是爲平衡,那麼根節點和左子樹節點都爲平衡EH (*T)->bf = L->bf = EH; break; case RH://若是右子樹高,那麼對根節點賦值爲0,對左子樹賦值爲+1,由於進行旋轉後,左子樹節點的右子樹會空。根節點EH (*T)->bf = EH; L->bf = LH; break; } Lr->bf = EH; L_Rotate(&(*T)->lchild); R_Rotate(T); } } void RightBalance(BiTree *T){ BiTree R,Rl; R = (*T)->rchild; switch(R->bf){ case RH: (*T)->bf = R->bf = EH; L_Rotate(T); break; case LH: Rl = R->lchild; switch(Rl->bf){ case LH: //若是是左子數高,那麼對根節點賦值爲-1,由於沒有右子樹,根節點將會出現左子樹爲空的狀況;左子樹旋轉後,會平衡爲EH (*T)->bf = EH; R->bf = RH; break; case EH://若是爲平衡,那麼根節點和左子樹節點都爲平衡EH (*T)->bf = R->bf = EH; break; case RH://若是右子樹高,那麼對根節點賦值爲0,對左子樹賦值爲+1,由於進行旋轉後,左子樹節點的右子樹會空。根節點EH (*T)->bf = LH; R->bf = EH; break; } Rl->bf = EH; R_Rotate(&(*T)->rchild); L_Rotate(T); } }