【修改】C实现平衡二叉树---AVL

本文介绍了一种使用C语言实现的AVL平衡二叉树,包括插入、查找、中序遍历、先序遍历、删除、平衡旋转等关键操作。详细解释了如何在插入元素时维护树的平衡,以及删除节点后的平衡处理方法。
/************************************************************************/  
/*                    C实现平衡二叉树---AVL                                                */  
/************************************************************************/  
#include <stdio.h>  
#include <stdlib.h>  
#define LH (+1)     /*左高*/
#define EH  0       /*等高*/
#define RH (-1)     /*右高*/
#define TRUE 1
#define FALSE 0
typedef int ElemType;  
typedef struct BiTNode                /*结点结构*/
{  
    ElemType data;                    /*结点数据*/
    int bf;                           /*平衡因子*/
    struct BiTNode *lchild,*rchild;   /*左右孩子指针*/
}BiTNode,*BiTree;  

/***********************************************************************
对以p为根的二叉树作右旋操作,处理之后
p指向新的根结点,即旋转处理之前的左子树的根结点
************************************************************************/
void R_Rotate(BiTree* p)  
{  
    BiTree lc = (*p)->lchild;  
    (*p)->lchild = lc->rchild;  
    lc->rchild = *p;  
    *p = lc;  
}  

/***********************************************************************
对以p为根的二叉树作左旋操作,处理之后
p指向新的根结点,即旋转处理之前的左子树的根结点
************************************************************************/
void L_Rotate(BiTree* p)  
{  
    BiTree rc = (*p)->rchild;  
    (*p)->rchild = rc->lchild;  
    rc->lchild = *p;  
    *p = rc;  
}  

/***********************************************************************
对以指针T所指结点为根的二叉树作左平衡旋转处理
本算法结束时,指针T指向新的根结点
************************************************************************/
void LeftBalance(BiTree* T)  
{  
    BiTree lc,rd;  
    lc = (*T)->lchild;      /*lc指向T的左子树根结点*/
    switch (lc->bf)  
    {  
        /*检查T的左子树的平衡度,并作相应平衡处理*/
		case LH:  /*新插入的结点在T的左孩子的左子树上,要作单右旋处理*/
			{  
				(*T)->bf = lc->bf = EH;  
				R_Rotate(T);  
				break;	
			}
		case RH:  /*新插入的结点在T的左孩子的右子树上,要作双旋处理*/
			{
				rd = lc->rchild;   /*rd指向T的左孩子的右子树的根*/
				switch(rd->bf)	   /*修改T极其左孩子的平衡因子*/
				{  
					case LH: 
						{
							(*T)->bf = RH;	
							lc->bf = EH;  
							break;	
						}
					case EH: 
						{
							(*T)->bf = lc->bf = EH;  
							break;	
						}
					case RH:  
						{
							(*T)->bf = EH;	
							lc->bf = LH;  
							break;	
						}
				}  
			}
		rd->bf = EH;  
		L_Rotate(&(*T)->lchild);     /*对T的左子树作左旋平衡处理*/
		R_Rotate(T);                 /*对T作右旋平衡处理*/
		break;	
    }  
}  


/***********************************************************************
  对以指针T所指结点为根的二叉树作右平衡旋转处理
  本算法结束时,指针T指向新的根结点
 ************************************************************************/
void RightBalance(BiTree* T)  
{  
    BiTree lc,rd;  
    lc= (*T)->rchild;   /*lc指向T的右子树根结点*/
    switch (lc->bf)  
    {  
        /*检查T的右子树的平衡度,并作相应平衡处理*/
        case RH:   /*新插入的结点在T的右孩子的右子树上,要作单左旋处理*/
			{
				(*T)->bf = lc->bf = EH;  
				L_Rotate(T);  
				break;	
			}
		
        case LH: /*新插入的结点在T的右孩子的左子树上,要作双旋处理*/
			{
				rd = lc->lchild;   /*rd指向T的右孩子的左子树的根*/
				switch(rd->bf)	    /*修改T极其右孩子的平衡因子*/
				{  
				    case LH:  
						{
							(*T)->bf = EH;	
							lc->bf = RH;  
							break;	
						}
				    case EH: 
						{
							(*T)->bf = lc->bf = EH;  
							break;	
						}
				    case RH: 
						{
							(*T)->bf = EH;	
							lc->bf = LH;  
							break;	
						}
				}  
			}
    rd->bf = EH;  
    R_Rotate(&(*T)->rchild);   /*对T的右子树作右旋平衡处理*/
    L_Rotate(T);               /*对T作左旋平衡处理*/
    break;  
    }  
}  

/***********************************************************************
若在平衡的二叉排序树T中不存在和e有相同关键字的结点,
则插入一个数据元素为e的新结点并返回1,否则返回0 。
若因插入而使二叉排序树失去平衡,则作平衡旋转处理,
变量taller反映T长高与否。
 ************************************************************************/
int InsertAVL(BiTree* T,ElemType e,int* taller)  
{  
    if ((*T)==NULL)  
    {    /*插入新结点,树长高,置taller为TRUE*/
        *T=(BiTree)malloc(sizeof(BiTNode));  
        (*T)->bf = EH;  
        (*T)->data = e;  
        (*T)->lchild = NULL;  
        (*T)->rchild = NULL;  
		*taller = TRUE;
    }  
    else if (e == (*T)->data)  
    {    /*树中已存在和e有相同关键字的结点则不再插入*/
        *taller = FALSE;  
        return FALSE;  
    }  
    else 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 0;  
        	}
        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 1;  
}  

  
/***********************************************************************
在平衡二叉树root中查找元素e,若存在则pos指向该节点
并返回TRUE,否则返回FALSE。
 ************************************************************************/
int FindNode(BiTree root,ElemType e,BiTree* pos)  
{  
    BiTree pt = root;  
    (*pos) = NULL;  
    while(pt)  
    {  
        if (pt->data == e)   /*找到节点,pos指向该节点并返回true */ 
        {  
            (*pos) = pt;  
            return TRUE;  
        }  
        else 
        {
			if (pt->data > e)  
            {  
                pt = pt->lchild;  
            }  
            else 
            {
				pt = pt->rchild;  
            }
        }
    }  
    return FALSE;  
}  

/***********************************************************************
在平衡二叉树中搜索关键字
 ************************************************************************/
void Find(BiTree root)
{
    BiTree pos=NULL;  
    int num;
    printf("Input the num to find:\n");
	scanf(" %d",&num);
    if(FindNode(root,num,&pos))
    {
        printf("\n%d is found\n",pos->data);  
    }
    else  
    {
        printf("\nNot find this Node\n");  
    }
}
/***********************************************************************
中根遍历平衡二叉树root,并输出结点
 ************************************************************************/
void InorderTra(BiTree root)  
{  
    if(root->lchild) 
    {
        InorderTra(root->lchild);  
    }
    printf("%d ",root->data);  
    if(root->rchild)  
    {
        InorderTra(root->rchild);  
    }
}   

/***********************************************************************
先根遍历平衡二叉树root,并输出结点(带空结点)
************************************************************************/
void PreorderTra(BiTree root)
{
    if(root == NULL)
    {
        printf("^ ");
        return ;
    }
	else
	{
	    printf("%d ",root->data);
		PreorderTra(root->lchild);
		PreorderTra(root->rchild);
	}
}


/***********************************************************************
在删除结点时进行左平衡处理
************************************************************************/
void LeftProcess1(BiTree *p,int *taller)	
{         
    BiTree p1,p2;
	if ((*p)->bf==1)
	{           
	    (*p)->bf=0;   
		*taller=1;  
	}
	else 
	{
	    if ((*p)->bf==0)
	    {         
	        (*p)->bf=-1;   
		    *taller=0;   
      	}
	    else		/*p->bf=-1*/
	    {
	    	p1=(*p)->rchild;
	    	if (p1->bf==0)			/*需作RR调整*/
			{    
			    (*p)->rchild=p1->lchild;
				p1->lchild=(*p);
				p1->bf=1;
				(*p)->bf=-1;
				(*p)=p1;
				*taller=0;
			}
			else 
			{
		    	if (p1->bf==-1)	             /*需作RR调整*/
		    	{
		    		(*p)->rchild=p1->lchild;
		    		p1->lchild=(*p);
				    (*p)->bf=p1->bf=0;
	    			(*p)=p1;
		  		  	*taller=1;
	    		}
	 			else					/*需作RL调整*/
				{
					p2=p1->lchild;
					p1->lchild=p2->rchild;
					p2->rchild=p1;
					(*p)->rchild=p2->lchild;
					p2->lchild=(*p);
					if (p2->bf==0)
					{
						(*p)->bf=0;
						p1->bf=0;
					}
					else
					{
					    if (p2->bf==-1)
				 	   {
				 		    (*p)->bf=1;
							p1->bf=0;
				 	   }
				  	  else
				  	  {
						    (*p)->bf=0;
							p1->bf=-1;
					    }
					}	
					p2->bf=0;
					(*p)=p2;
					*taller=1;
				}
			}
		}
	}
}


/***********************************************************************
在删除结点时进行右平衡处理
************************************************************************/
void RightProcess1(BiTree *p,int *taller)
{
	BiTree p1,p2;
	if ((*p)->bf==-1)
	{    
	    (*p)->bf=0;  
		*taller=-1;   
	}
	else 
	{
	    if ((*p)->bf==0)
	    {    
	        (*p)->bf=1;  
	    	*taller=0;   
	    }
	    else		/*(*p)->bf=1*/
	    {
		    p1=(*p)->lchild;
		    if (p1->bf==0)			/*需作LL调整*/
	    	{    
	    	    (*p)->lchild=p1->rchild;    
				p1->rchild=(*p);
		        p1->bf=-1;
				(*p)->bf=1;    
				(*p)=p1;       
				*taller=0;   
				}
		    else 
	    	{
		        if (p1->bf==1)		/*需作LL调整*/
	            {      
    	            (*p)->lchild=p1->rchild;   
	        		p1->rchild=(*p);
		            (*p)->bf=p1->bf=0;   
	        	    (*p)=p1;        
    	    		*taller=1;     
	        	}
		        else					/*需作LR调整*/
		        {    
		            p2=p1->rchild;     
			    	p1->rchild=p2->lchild;
		            p2->lchild=p1;  
			    	(*p)->lchild=p2->rchild;   
			    	p2->rchild=(*p);
			        if (p2->bf==0)
			        {     
			            (*p)->bf=0;
			    		p1->bf=0;  
			    	}
    		    	else 
    		    	{
	    		    	if (p2->bf==1)
	    		    	{	 
	    			        (*p)->bf=-1;
	    			    	p1->bf=0;
	    		    	}
		    		    else
		    		    {	 
	    			       (*p)->bf=0;
	    			      	p1->bf=1;	
	    			    }
	    		    }
	    		    p2->bf=0;   
	    		    (*p)=p2;      
	    		    *taller=1;  
	    	    }    
		    }
	    }
	}
}


/****************************************************************************
由DeleteAVL()调用,用于处理被删结点左右子树均不空的情况
*****************************************************************************/
void Delete2(BiTree q,BiTree *r,int *taller)  
{
	if ((*r)->rchild==NULL)
	{
		q->data=(*r)->data;
		q=*r;
		(*r)=(*r)->lchild;
		free(q);
		*taller=1;
	}
	else
	{
		Delete2(q,&((*r)->rchild),taller);
		if (*taller==1) 
		{
			RightProcess1(r,taller);
		}
	}
}

/****************************************************************************
在AVL树p中删除关键字为x的结点
*****************************************************************************/
int DeleteAVL(BiTree *p,ElemType x,int *taller)
{
	int k;
	BiTree q;
	if ((*p)==NULL) 
	{
		return 0;
	}
	if (x < (*p)->data)
	{            
	    k=DeleteAVL(&((*p)->lchild),x,taller);
		if (*taller==1) 
		{
			LeftProcess1(p,taller);
		}
		return k;     
	}
	else
	{
		if (x > (*p)->data)
		{		    
			k=DeleteAVL(&((*p)->rchild),x,taller);
			if (*taller==1) 
			{
				RightProcess1(p,taller);  
			}
			return k;	   
		}
		else			/*找到了关键字为x的结点,由p指向它*/
		{				
			q=(*p);
			if ((*p)->rchild==NULL)		/*被删结点右子树为空*/
			{		
				(*p)=(*p)->lchild;	  
				free(q);	
				*taller=1;	
			}
			else 
			{
				if ((*p)->lchild==NULL)	/*被删结点左子树为空*/
				{	  
					(*p)=(*p)->rchild;	 
					free(q);	 
					*taller=1;	 
				}
			    else					   /*被删结点左右子树均不空*/
			    {	
					Delete2(q,&(q->lchild),taller);
					if (*taller==1) 
					{
						LeftProcess1(&q,taller);    
					}
					(*p)=q;   
				}
			}
			return 1;
		}	
	}
}



int main()  
{  
    int i;
	int nArr[] = {1,23,45,43,38,95,23,42,55};  
    BiTree root=NULL;//,pos=NULL;  
    int taller;  
    for (i=0;i<9;i++)  
    {  
        InsertAVL(&root,nArr[i],&taller);  
    }  

	while(1)
	{
  		printf("1.InorderTra\n");
		printf("2.PreorderTra\n");
		printf("3.Insert\n");
		printf("4.Delete:\n");
		printf("5.Find:\n");
	    scanf(" %d",&i);
		switch(i)
			{
			    case 1:
					{
						printf("InorderTra:\n");
						InorderTra(root); 
						printf("\n");
						break;
					}
			    case 2:
					{
						printf("PreorderTra:\n");
						PreorderTra(root);
						printf("\n");
						break;
					}
			    case 3:
					{
						printf("Insert:\n");
						scanf(" %d",&i);
						InsertAVL(&root,i,&taller);  
						break;
					}
			    case 4:
					{
						printf("Delete:\n");
						scanf(" %d",&i);
						DeleteAVL(&root,i,&taller);
						break;
					}
			    case 5:
					{
						Find(root);
						break;
					}
				default:
					{
						break;
					}
			}
	}
    return 0;  
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值