- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- /* 二叉平衡树节点的定义 */
- typedef struct _AVLNode{
- int data;
- int bf;/*平衡因子*/
- struct _AVLNode *lchild,*rchild;
- }AVLNode,*AVLTree;
- /*创建一个二叉搜索树节点,x为关键字值 */
- AVLTree Create(int x)
- {
- AVLTree avl=(AVLTree)malloc(sizeof(AVLNode));
- if(avl==NULL)
- {
- perror("创建失败");
- exit(1);
- }
- avl->data=x;
- avl->bf=0;
- avl->lchild=avl->rchild=NULL;
- return avl;
- }
- /*左旋转函数*/
- void LRotation(AVLTree *avl,int *unbalance)
- {
- AVLTree u,r=(*avl)->lchild;
- if(r->bf==1)//LL 旋转
- {
- (*avl)->lchild=r->rchild;
- r->rchild=*avl;
- (*avl)->bf=0;
- (*avl)=r;/*(*avl)指向新子树的根*/
- }
- else/*LR旋转*/
- {
- u=r->rchild;
- r->rchild=u->lchild;
- u->lchild=r;
- (*avl)->lchild=u->rchild;
- u->rchild=*avl;
- switch(u->bf)
- {
- case 1:
- (*avl)->bf=-1;
- r->bf=0;
- break;
- case 0:
- (*avl)->bf=r->bf=0;
- break;
- case -1:
- (*avl)->bf=0;
- r->bf=1;
- }
- *avl=u;/*(*avl)指向新子树的根*/
- }
- (*avl)->bf=0;
- *unbalance=0;
- }
- void RRotation(AVLTree *avl,int *unbalance)
- {
- AVLTree u,r=(*avl)->rchild;
- if(r->bf==-1)//RR 旋转
- {
- (*avl)->rchild=r->lchild;
- r->lchild=(*avl);
- (*avl)->bf=0;
- (*avl)=r;/*(*avl)指向新子树的根*/
- }
- else
- {
- u=r->lchild;
- r->lchild=u->rchild;
- u->rchild=r;
- (*avl)->rchild=u->lchild;
- u->lchild=(*avl);
- switch(u->bf)
- {
- case -1:
- (*avl)->bf=-1;
- r->bf=0;
- break;
- case 0:
- (*avl)->bf=r->bf=0;
- break;
- case 1:
- (*avl)->bf=0;
- r->bf=1;
- }
- (*avl)=u;/*(*avl)指向新子树的根*/
- }
- (*avl)->bf=0;
- *unbalance=0;
- }
- void Insert(AVLTree* avl,int x,int *unbalance)
- {
- if(*avl==NULL)
- {/*生成新结点再插入*/
- *avl=Create(x);
- *unbalance=1;
- }
- else if(x<((*avl)->data))/*新结点插入左子树*/
- {
- Insert(&((*avl)->lchild),x,unbalance);
- if(*unbalance)
- {
- switch((*avl)->bf)
- {
- case -1:
- (*avl)->bf=0;
- *unbalance=0;
- break;
- case 0:
- (*avl)->bf=1;
- break;
- case 1:
- LRotation(avl,unbalance);
- }
- }
- }
- else if(x==(*avl)->data)/*元素存在直接返回*/
- {
- return ;
- }
- else/*新结点插入右子树*/
- {
- Insert(&((*avl)->rchild),x,unbalance);
- if(*unbalance)
- {
- switch((*avl)->bf)
- {
- case 1:(*avl)->bf=0;
- *unbalance=0;break;
- break;
- case 0:
- (*avl)->bf=-1;
- break;
- case -1:
- RRotation(avl,unbalance);
- }
- }
- }
- }
- /*中序遍历 */
- void InOrder(AVLTree bst)
- {
- if(bst==NULL)
- return ;
- else
- {
- InOrder(bst->lchild);
- printf("%d ",bst->data);
- InOrder(bst->rchild);
- }
- }
- /*前序遍历 */
- void PreOrder(AVLTree bst)
- {
- if(bst==NULL)
- return ;
- else
- {
- printf("%d ",bst->data);
- PreOrder(bst->lchild);
- PreOrder(bst->rchild);
- }
- }
- int main()
- {
- AVLTree avl=NULL;
- int balance;
- Insert(&avl,45,&balance);
- Insert(&avl,28,&balance);
- Insert(&avl,15,&balance);
- Insert(&avl,12,&balance);
- Insert(&avl,14,&balance);
- Insert(&avl,13,&balance);
- Insert(&avl,11,&balance);
- Insert(&avl,47,&balance);
- Insert(&avl,57,&balance);
- Insert(&avl,46,&balance);
- InOrder(avl);
- printf("\n");
- PreOrder(avl);
- }
二叉平衡树的删除与插入类似,先采用二叉搜索树的删除方法,删除结点,再在必要时通过重新平衡,恢复平衡性和排序性。当删除X有两个孩子时,使用替代法,将问题转化为删除只有一个孩子的结点的问题,然后删除之。由q指向实际被删除的结点,它最多只有一个非空子树,当结点q由它的孩子取代后,该树变矮,这种情况会影响其祖先的平衡性,应重新平衡。使用short变量来记录对其双亲(p)平衡性的影响。
同插入的情况一样,我们通过以下三种情况来分析二叉平衡树的删除。
情况一:结点p的平衡因子为0
从p的子树上删除结点后,该子树变矮,但以p为根的子树的高度不变,只是平衡因子变化了。只要修改平衡因子即可。令short变量为0,表示算法终止。如图所示:
情况二:从结点p的较高子树上删除一个结点
从p的较高子树上删除节点后,树的高度降低,但是一p为根的子树依然是平衡的。因此将p的平衡因子置位1。因为p的平衡因子改变了可能影响其双亲的平衡因子,故需要是short为1,表示继续检查p的双亲为根的子树的平衡性是否因为p的变矮而破坏。如图所示:
情况三:从结点p的矮的子树上删除一个结点
从p的较矮子树上删除一个结点,以p为根的子树的平衡性被破坏,要通过旋转来恢复这棵子树的平衡性。设r是p的较高子树,根据r的平衡因子,可以进一步细分一下三种。
(1)结点r的平衡因子为0
则应采用单一旋转,并修改p和r的平衡因子的值。重新平衡后,新子树与原子树有相同的高度,不会影响二叉平衡树的其余部分,令short=0,算法终止。如图所示:
(2)结点r的平衡因子和p的平衡因子同号
仍采用单一旋转,旋转后p和r的平衡因子均为0.重新平衡后,新子树变矮,故short=1,需要继续考察p的双亲的平衡性。
(3)结点r的平衡性和p的平衡性异号
则采用双重旋转。令u是r的较高子树的根,它将成为新子树的根,取代p为根的子树,u的平衡因子为0,p和r的平衡因子做相应的修改,这棵以u为根的子树是平衡的,但高度变矮了。故short=1;继续向根方向考察。如图所示: