平衡二叉树

来源:互联网 发布:做自己想做的梦 知乎 编辑:程序博客网 时间:2024/05/01 13:20

平衡二叉树又称AVL树。它或者是颗空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的深度之差的绝对值不超过1。若将二叉树节点的平衡因子BF定义为该节点的左子树的深度减去它的右子树的深度,则平衡二叉树上所有节点的平衡因子只可能为-1,0,1.只要二叉树上有一个节点的平衡因子的绝对值大于1,那么这颗平衡二叉树就失去了平衡。

假设我们已经有棵平衡二叉树,现在让我们来看看插入节点后,原来节点失去平衡后,我们进行选择的处理方式。

平衡二叉树多用于查找数据,所以平衡二叉树又是颗二叉排序树。

那么如何创建一颗平衡二叉树呢?

创建平衡二叉树,我们采用依次插入节点的方式进行。而平衡二叉树上插入节点采用递归的方式进行。递归算法如下:

(1)      若该树为一空树,那么插入一个数据元素为e的新节点作为平衡二叉树的根节点,树的高度增加1。

(2)      若待插入的数据元素e和平衡二叉树(BBST)的根节点的关键字相等,那么就不需要进行插入操作。

(3)      若待插入的元素e比平衡二叉树(BBST)的根节点的关键字小,而且在BBST的左子树中也不存在和e有相同关键字的节点,则将e插入在BBST的左子树上,并且当插入之后的左子树深度增加1时,分别就下列情况处理之。

(a)    BBST的根节点的平衡因子为-1(右子树的深度大于左子树的深度):则将根节点的平衡因子更改为0,BBST的深度不变;

(b)    BBST的根节点的平衡因子为0(左右子树的深度相等):则将根节点的平衡因子修改为1,BBST的深度增加1;

(c)    BBST的根节点的平衡因子为1(左子树的深度大于右子树的深度):若BBST的左子树根节点的平衡因子为1,则需要进行单向右旋转平衡处理,并且在右旋处理后,将根节点和其右子树根节点的平衡因子更改为0,树的深度不变;

若BBST的左子树根节点的平衡因子为-1,则需进行先向左,后向右的双向旋转平衡处理,并且在旋转处理之后,修改根节点和其左,右子树根节点的平衡因子,树的深度不变;

(4)      若e的关键字大于BBST的根节点的关键字,而且在BBST的右子树中不存在和e有相同关键字的节点,则将e插入到BBST的右子树上,并且当插入之后的右子树深度加1时,分别就不同的情况处理之。

(a)      BBST的根节点的平衡因子是1(左子树的深度大于右子树的深度):则将根节点的平衡因子修改为0,BBST的深度不变;

(b)      BBST的根节点的平衡因子是0(左右子树的深度相等):则将根节点的平衡因子修改为-1,树的深度加1;

(c)      BBST的根节点的平衡因子为-1(右子树的深度大于左子树的深度):若BBST的右子树根节点的平衡因子为1,则需要进行两次选择,第一次先向右旋转,再向左旋转处理,并且在旋转处理之后,修改根节点和其左,右子树根节点的平衡因子,树的深度不变;

若BBST的右子树根节点的平衡因子为1,则需要进行一次向左的旋转处理,并且在左旋之后,更新根节点和其左,右子树根节点的平衡因子,树的深度不变;

/*首先平衡二叉树是一个二叉排序树;其基本思想是:在构建二叉排序树的过程中,当每插入一个节点时,先检查是否因为插入而破坏了树的平衡性,若是,找出最小不平衡树,进行适应的旋转,使之成为新的平衡二叉树。*/#include<stdio.h>#include<stdlib.h>#define LH 1#define EH 0#define RH -1typedef struct BTNode{ int data; int BF;//平衡因子(balance factor) struct BTNode *lchild,*rchild;}BTNode,*BTree;void R_Rotate(BTree *p)//以p为根节点的二叉排序树进行右旋转{ BTree L; L=(*p)->lchild; (*p)->lchild=L->rchild; L->rchild=(*p); *p=L;//p指向新的根节点}void L_Rotate(BTree *p)//以p为根节点的二叉排序树进行左旋转{ BTree R; R=(*p)->rchild; (*p)->rchild=R->lchild; R->lchild=(*p); *p=R;}void LeftBalance(BTree *T){ BTree L,Lr; L=(*T)->lchild; switch(L->BF) {  //检查T的左子树平衡度,并作相应的平衡处理  case LH://新节点插入在T的左孩子的左子树上,做单右旋处理   (*T)->BF=L->BF=EH;   R_Rotate(T);   break;  case RH://新插入节点在T的左孩子的右子树上,做双旋处理   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;   L_Rotate(&(*T)->lchild);   R_Rotate(T); }}void RightBalance(BTree *T){ BTree R,Rl; R=(*T)->rchild; switch(R->BF) {  case RH://新节点插在T的右孩子的右子树上,要做单左旋处理   (*T)->BF=R->BF=EH;   L_Rotate(T);   break;  case LH://新节点插在T的右孩子的左子树上,要做双旋处理   Rl=R->lchild;   switch(Rl->BF)   {    case LH:     (*T)->BF=EH;     R->BF=RH;     break;    case EH:     (*T)->BF=R->BF=EH;     break;    case RH:     (*T)->BF=LH;     R->BF=EH;     break;   }   Rl->BF=EH;   R_Rotate(&(*T)->rchild);   L_Rotate(T); }}int InsertAVL(BTree *T,int e,int *taller)//变量taller反应T长高与否{ if(!*T) {  *T=(BTree)malloc(sizeof(BTNode));  (*T)->data=e;  (*T)->lchild=(*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  {   //应在T的右子树中搜寻   if(!InsertAVL(&(*T)->rchild,e,taller))    return 0;   if(*taller)//插入右子树,且右子树长高   {    switch((*T)->BF)    {     case LH://原本左子树比右子树高,现在左右子树等高      (*T)->BF=EH;      *taller=0;      break;     case EH://原本左右子树等高,现在右子树变高      (*T)->BF=RH;      *taller=1;      break;     case RH://原本右子树比左子树高,现在需做右平衡处理      RightBalance(T);      *taller=0;      break;    }   }  } } return 1;}int Find(BTree T,int key){ if(!T)  return 0; else if(T->data==key)  return 1; else if(T->data<key)  return Find(T->rchild,key); else  return Find(T->lchild,key);}void Output(BTree T){ if(T) {  printf("%d",T->data);  if(T->lchild||T->rchild)  {   printf("(");   Output(T->lchild);   printf(",");   Output(T->rchild);   printf(")");  } }}int main(int argc,char *argv[]){ int i; int A[]={3,2,1,4,5,6,7,10,9,8}; BTree T=NULL; int taller; for(i=0;i<sizeof(A)/sizeof(int);i++)  InsertAVL(&T,A[i],&taller); Output(T); printf("\n"); if(Find(T,6))  printf("6 is find in the AVL tree!\n"); else   printf("6 is not find in the AVL tree!\n"); return 0;}


0 0