查找-平衡二叉树

当用户进行二叉排序树的创建时,对于同一组数据,不同的插入次序的序列生成的不同形态的二叉排序树。

而不同形态平均查找长度一般是不同的,最坏形态的平均查找长度是(n+1)/2,这显然不是我们想要的情况,所以我们需要对二叉排序树进行改进。 

那么怎样提高二叉排序树的查找效率呢?我们需要让二叉树的形状均衡。

平衡二叉树(AVL树):所有结点的左右子树深度之差的绝对值<=1 .

平衡因子:该结点左子树与右子树高度差。

对于一颗有n个结点的AVL树,其高度保持在O(logN)数量级,ASL也保持在O(logN)量级。

是二叉平衡树,同时是二叉排序树。是二叉排序树,可能不是平衡二叉树。

首先是辅助宏的定义:

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OVERFLOW -1
#define UNDERFLOW -2
#define NULL 0
#define LH 1 //左高
#define EH 0  //等高
#define RH -1 //右高
typedef int Status;
typedef int KeyType;
typedef char* InfoType;

平衡二叉树的存储结构定义:

//平衡二叉排序树的存储结构定义
typedef struct{
   KeyType key;
   InfoType otherinfo; //附加信息
}ElemType;
typedef struct BiTNode{ 
   ElemType data;
   struct BiTNode *lchild,*rchild;
   int bf; //平衡因子
}BiTNode,*BiTree;
typedef BiTNode BSTNode;
typedef BiTree BSTree; 

平衡二叉树的构造:

二叉排序树进行构造,每插入一个结点,检查该结点是否不平衡。若导致不平衡 则找最小不平衡树,通过旋转使该最小的不平衡树平衡。

对以*p为根的二叉排序树作左旋处理,处理之后p指向新的树根结点,即旋转处理之前的右子树的根结点 。

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

对以*p为根的二叉排序树作右旋处理,处理之后p指向新的树根结点,即旋转处理之前的左子树的根结点.

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

若在平衡二叉排序树T中不存在和e有相同关键字的结点,则插入一个数据元素 为e的新结点,并返回OK 否则返回ERROR 若因插入而使二叉排序树失去平衡,则作平衡旋转处理,布尔变量taller反映T长高与否。

Status InsertAVL(BSTree &T,ElemType e,bool &taller)
{
   /*若在平衡二叉排序树T中不存在和e有相同关键字的结点,则插入一个数据元素
   为e的新结点,并返回OK 否则返回ERROR 若因插入而使二叉排序树失去平衡,则
   作平衡旋转处理,布尔变量taller反映T长高与否 */
   if(!T)
   {
       //若插入新结点 树长高 置taller为TRUE
       if(!(T=(BSTree)malloc(sizeof(BSTNode))))
           exit(OVERFLOW);
       T->bf=EH;
       T->data=e;
       T->lchild=T->rchild=NULL;
       taller=TRUE;
   }
   else
   {
       if(e.key==T->data.key) //树中已存在和e有相同关键子的结点
       {
           taller=FALSE; //不再插入
           return ERROR;
       }
       else if(e.key<T->data.key) //应继续在*T的左子树中进行搜索
       {
	   if(!InsertAVL(T->lchild,e,taller)) //未插入
               return ERROR;
           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 ERROR;
	  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 OK;
}

对以指针T所指结点为根的二叉树作左平衡旋转处理,本算法结束时,指针T指向,本算法结束时,指针T指向新结点..

void LeftBalance(BSTree &T)
{
    //对以指针T所指结点为根的二叉树作左平衡旋转处理,本算法结束时,指针T指向
    //新结点
    BSTNode *lc=T->lchild,*rd; //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的左子树作左旋平衡处理 此处不能用lc代替!!
            R_Rotate(T); //对*T作右旋平衡处理
            break;
    }
}

对以指针T所指结点为根的二叉树作右平衡旋转处理,本算法结束时,指针T指向新结点.

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

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值