码迷,mamicode.com
首页 > 其他好文 > 详细

7. 蛤蟆的数据结构进阶七平衡二叉树

时间:2015-08-07 00:29:23      阅读:203      评论:0      收藏:0      [点我收藏+]

标签:

7. 蛤蟆的数据结构进阶七平衡二叉树

         本地名言:“金钱的贪求(这个毛病,目前我们大家都犯得很凶)和享乐的贪求,促使我们成为它们的奴隶,也可以说,把我们整个身心投入深渊。唯利是图,是一种痼疾,使人卑鄙,但贪求享乐,更是一种使人极端无耻,不可救药的毛病。 --郎加纳斯”

         我们来看下传说中的平衡二叉树,为什么说他传说中呢?因为蛤蟆接触ORACLE数据库比较多,而ORACLE数据中用到最多的索引就是平衡二叉树,所以嘛。

        欢迎转载,转载请标明出处:http://write.blog.csdn.net/postedit/47324129

1.  平衡二叉树

平衡二叉树(BalancedBinary Tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。构造与调整方法平衡二叉树的常用算法有红黑树、AVL、Treap等。 最小二叉平衡树的节点的公式如下F(n)=F(n-1)+F(n-2)+1 这个类似于一个递归的数列,可以参考Fibonacci数列,1是根节点,F(n-1)是左子树的节点数量,F(n-2)是右子树的节点数量。

 

 

 

2.  代码实现

2.1         main

输入1进行调用CreatBST函数来创建平衡二叉树,输入2 调用SearchBST函数进行查找,输入3调用InsertAVL函数进行插入,输入4调用DeleteAVL进行删除,输入5退出。

输入其他则提出输入错误,请重新选择。

简单图1示如下

技术分享

2.2         R_Rotate(BSTree &p)

 

 

  //对以*p为根的二叉排序树作右旋处理

 

 

 

2.3         L_Rotate(BSTree &p)

 

 

 //对以*p为根的二叉排序树作左旋处理

 

 

 

2.4         LeftBalance(BSTree &T)

该函数实现对以指针T所指结点为根的二叉树作左平衡旋转处理

输入的那个节点的平衡度为1,但是又再其左边插入了一个节点,使失去了平衡。

                  获得该节点的子节点。判断该子节点的平衡度。

         如果子节点平衡度为1则,将该节点和子节点的平衡度设置为0,然后调用R_Rotate函数进行单向右旋处理(LL型)。

         如果子节点平衡度为-1则,先进行左旋,然后右旋处理(双向旋转 LR型)。

 

2.5         R_Rotate

为根的二叉排序树作右旋处理。

2.6         L_Rotate

为根的二叉排序树作左旋处理。

 

2.7         RightBalance(BSTree &T)

//对以指针T所指结点为根的二叉树作右平衡旋转处理

同LeftBalance函数。有两种类型。(RR型和RL型)。

 

 

2.8         InsertAVL(BSTree &T,inte,bool &taller)

如果为空,则创建节点,插入成功。

如果不为空,

则判断是否在平衡二叉树中已经存在。如果存在则设置taller=false.然后退出返回0。

   如果再平衡二叉树中不存在,则判断插入的值与根节点大小,如果小于则递归调用InsertAVL函数从左节点开始,如果大于则递归调用InsertAVL函数从右节点插入。(最后是肯定要一个为空的节点上进行插入的,不存在替换的情况,如果替换说明相等,但是相等时不会插入的)

如果插入成功,则设置taller为true,然后计算平衡度。

平衡度是倒退。在左子节点插入后,判断当前该节点的平衡值,如果之前是LH,说明原本是左边高现在又往左边插入,需要调用leftbalance函数进行处理。其他情况类似,如果再在右子节点插入后,判断当前该节点的平衡值,如果之前是RH,说明原本是右边高现在又往右边插入,也需要调用RightBalance函数进行处理

 

 

 

 

 

2.9         SearchBST(BSTree &T,intkey)

该函数用户查找元素key是否在树T中

存在则返回,否则判断是否递归进行左子树后者右子树查询。

 

 

 

2.10   CreatBST(BSTree &T)

 

以输入-1为二叉树建立的结束。

然后调用InsertAVL函数插入到平衡二叉树中。

 

2.11   LeftBalance_div(BSTree&p,int &shorter)

//删除结点时左平衡旋转处理

2.12   RightBalance_div(BSTree&p,int &shorter)

//删除结点时右平衡旋转处理

2.13   Delete(BSTree q,BSTree  &r,int &shorter)

//删除结点

如果删除节点的右子节点的右子节点为空,则直接将右子节点提升上来,将右子节点的的左子节点放置到之前右子节点的位置即可。

如果删除节点的右子节点的右子节点不为空,则递归调用Delete函数,然后调用RightBalance_div。  

 

 

 

 

 

 

2.14   DeleteAVL(BSTree &p,intx,int &shorter)

对平衡二叉树的删除操作。

如果删除点的右子树为空,则直接重接它的左子树即可。

如果左子树为空个,则重接它的右子树即可。

如果都不为空,则调用Delete函数。最后调用LeftBalance_div。

如果本次没找到则进行即可查找。

 

2.15   PrintBST

该函数用于输出二叉树。

递归调用进行输出。

 

 

 

 

 

 

3.  源码

#include<stdio.h>

#include<malloc.h>

#include<stdlib.h>

 

 

#defineEQ(a,b)((a)==(b))

#defineLT(a,b)  ((a)<(b))

#defineLQ(a,b)  ((a)>(b))

#defineLH+1     //左高

#defineEH0      //等高

#defineRH-1     //右高

#defineNULL 0

 

 

///////////////////////////// 定义结构体 ///////////////////////////

typedefstruct BSTNode

{

    intdata;

    intbf;                        //结点的平衡因子

    struct BSTNode*lchild,*rchild;//左、右孩子指针

}BSTNode,*BSTree;

 

 

///////////////////////////  函数声明  ///////////////////////////

void R_Rotate(BSTree&p);   //对以*p为根的二叉排序树作右旋处理

void L_Rotate(BSTree&p);   //对以*p为根的二叉排序树作左旋处理

void LeftBalance(BSTree&T);//对以指针T所指结点为根的二叉树作左平衡旋转处理

void RightBalance(BSTree&T);//对以指针T所指结点为根的二叉树作右平衡旋转处理

bool InsertAVL(BSTree&T,int e,bool&taller);//插入结点e

bool SearchBST(BSTree&T,int key);//查找元素key是否在树T中

void PrintBST(BSTreeT,int m);//按树状打印输出二叉树的元素

void CreatBST(BSTree&T);   //创建平衡二叉树,(注意:以输入-1为二叉树建立的结束)

void LeftBalance_div(BSTree&p,int &shorter);//删除结点时左平衡旋转处理

void RightBalance_div(BSTree&p,int &shorter);//删除结点时右平衡旋转处理

void Delete(BSTreeq,BSTree &r,int &shorter);//删除结点

int DeleteAVL(BSTree&p,int x,int&shorter);//平衡二叉树的删除操作

 

/////////////////////////////////////////////////////////////////////

 

 

 

void main()

{

    intinput,search,m;

    booltaller=false;

         intshorter=0;

    BSTreeT,T1,T2;

    T=(BSTree)malloc(sizeof(BSTNode));

    T=T1=T2=NULL;

         while(1)

         {   system("cls");

    printf("            ******************************************\n");

         printf("             *1.创建\t2.查找\t3.插入\t4.删除\t5.退出*\n");

    printf("            ******************************************\n");

       printf("请输入您所需的操作功能:\t");

        scanf("%d",&input);getchar();  

                   switch(input)

                   {

                      case 1:

                               CreatBST(T);break;

                      case 2:

                               printf("请输入你要查找的关键字");

              scanf("%d",&search); getchar();

              if(SearchBST(T,search)) printf("该二叉树中存在关键字%d,查找成功!\n",search);

              else printf("查找失败!\n");

              break;

                      case 3:

              printf("请输入你要插入的关键字");

              scanf("%d",&search); getchar();

              InsertAVL(T,search,taller); m = 0;

                               PrintBST(T,m);break;

                      case 4:

                               printf("请输入你要删除的关键字");

                               scanf("%d",&search);getchar();

                               DeleteAVL(T,search,shorter);

                               m=0; PrintBST(T,m);break;

                      case 5:

              printf("\t\tbyebye!\n");break;

                      default:printf("输入错误,请重新选择。");break;

                   }

                   if(input== 5) break;

                   printf("\t\t按任意键继续...");getchar();

         }

 

 

}

 

 

//对以*p为根的二叉排序树作右旋处理

void R_Rotate(BSTree&p)

{

    BSTreelc;            

    lc = p->lchild;         //lc指向的*p左子树根结点

    p->lchild= lc->rchild; //rc的右子树挂接为*p的左子树

   lc->rchild = p; p =lc; //p指向新的结点

}

 

//对以*p为根的二叉排序树作左旋处理

void L_Rotate(BSTree&p)

{

    BSTreerc;            

    rc = p->rchild;         //rc指向的*p右子树根结点

    p->rchild= rc->lchild; //rc的左子树挂接为*p的右子树

   rc->lchild = p; p =rc; //p指向新的结点

}

 

//对以指针T所指结点为根的二叉树作左平衡旋转处理

void LeftBalance(BSTree&T)

{

    BSTreelc,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作右旋平衡处理

    }

}

 

//对以指针T所指结点为根的二叉树作右平衡旋转处理

void RightBalance(BSTree&T)

{

    BSTreerc,ld;

    rc = T->rchild;         //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的右子树作左旋平衡处理

       L_Rotate(T);       //*T作左旋平衡处理

    }

}

 

 

//插入结点e,若T中存在和e相同关键字的结点,则插入一个数据元素为e的新结点,并返回1,否则返回0

bool InsertAVL(BSTree&T,inte,bool&taller)

{

    if(!T)//插入新结点,树长高,置tallertrue

    {

        T =(BSTree)malloc(sizeof(BSTNode));

        T->data= e;

        T->lchild= T->rchild =NULL;

        T->bf= EH; taller =true;

    }

    else

    {

        if(EQ(e,T->data))                //树中已存在和有相同关键字的结点

        { taller =false;printf("已存在相同关键字的结点\n");return0; }//则不再插入

        if(LT(e,T->data))                //应继续在*T的左子树中进行搜索

        {

            if(!InsertAVL(T->lchild,e,taller))return0;//未插入

            if(taller)                   //已插入到*T的左子树中且左子树长高

               switch(T->bf)            //检查*T的平衡度

           {

                 caseLH:                //原本左子树比右子树高,需要作左平衡处理

                     LeftBalance(T);taller =false;break;

                 caseEH:                //原本左子树、右子等高,现因左子树增高而使树增高

                     T->bf =LH; taller =true; break;

                 caseRH:                //原本右子树比左子树高,现左、右子树等高

                      T->bf=EH; taller =false; break;

            }//switch(T->bf)

        }//if

        else                              //应继续在*T的右子树中进行搜索

        {

            if(!InsertAVL(T->rchild,e,taller))return0;//未插入

            if(taller)                   //已插入到*T的右子树中且右子树长高

               switch(T->bf)            //检查*T的平衡度

           {

                  caseLH:               //原本左子树比右子树高,现左、右子树等高

                       T->bf= EH; taller =false; break;

                  caseEH:               //原本左子树、右子等高,现因右子树增高而使树增高

                       T->bf= RH; taller =true; break;

                  caseRH:               //原本右子树比左子树高,需要作右平衡处理

                       RightBalance(T);taller =false;break;

            }//switch(T->bf)

        }//else

    }//else

    return1;

}//InsertAVL

 

//查找元素key是否在树T中

bool SearchBST(BSTree&T,intkey)

{

    if(!T) return false;

    else if(EQ(key,T->data))returntrue;

    else if(LT(key,T->data))returnSearchBST(T->lchild,key);

    else returnSearchBST(T->rchild,key);

}

 

 

//按树状打印输出二叉树的元素,m表示结点所在层次,初次调用时m=o

void PrintBST(BSTreeT,intm)

{

    inti;

    if(T->rchild)PrintBST(T->rchild,m+1);

    for(i= 1; i<=m; i++) 

       printf("     ");//打印 i 个空格以表示出层次

    printf("%d\n",T->data);//打印 T 元素,换行

    if(T->lchild)

       PrintBST(T->lchild,m+1);

  

}

 

 

//创建平衡二叉树,(注意:以输入-1为二叉树建立的结束)

void CreatBST(BSTree&T)

{

    inte,m;

    booltaller=false;

    T =NULL;

    printf("\n请输入关键字(-1结束建立平衡二叉树):");

    scanf("%d",&e);getchar();

    while(e!= -1)

    {

       InsertAVL(T,e,taller);

       printf("\n请输入关键字(-1结束建立平衡二叉树):");

        scanf("%d",&e);getchar();taller=false;

    }

    m=0;

    printf("平衡二叉树创建结束,横向打印出树状结构:\n");

    if(T)  PrintBST(T,m);

    else  printf("这是一棵空树.\n");

}

 

 

//删除结点时左平衡旋转处理

void LeftBalance_div(BSTree&p,int&shorter)

{

         BSTree  p1,p2;

         if(p->bf==1)//p结点的左子树高,删除结点后pbf1,树变矮

         { p->bf=0;shorter=1;}

         else if(p->bf==0)//p结点左、右子树等高,删除结点后pbf1,树高不变

         { p->bf=-1;shorter=0;}

         else  //p结点的右子树高

         {

                   p1=p->rchild;//p1指向p的右子树

                   if(p1->bf==0)//p1结点左、右子树等高,删除结点后pbf-2,进行左旋处理,树高不变

                   {

                            L_Rotate(p);

                            p1->bf=1;p->bf=-1;shorter=0;

        }

                   else if(p1->bf==-1)//p1的右子树高,左旋处理后,树变矮

        {

                            L_Rotate(p);

           p1->bf=p->bf=0;shorter=1;

        }

                   else //p1的左子树高,进行双旋处理(先右旋后左旋),树变矮

        {

                            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; shorter=1;

                   }

  }

 

}

 

//删除结点时右平衡旋转处理

void RightBalance_div(BSTree&p,int&shorter)

{

         BSTree  p1,p2;

         if(p->bf==-1)

         { p->bf=0;shorter=1;}

    else if(p->bf==0)

         { p->bf=1;shorter=0;}

    else

    {

                   p1=p->lchild;

        if(p1->bf==0)

        {

                            R_Rotate(p);

           p1->bf=-1; p->bf=1; shorter=0;

                   }

        else if(p1->bf==1)

        {

                            R_Rotate(p);

           p1->bf=p->bf=0;shorter=1;

        }

        else

        {

           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; shorter=1;

                   }

         }

}

//删除结点

void Delete(BSTreeq,BSTree  &r,int&shorter)

{

         if(r->rchild==NULL)

    {

                   q->data=r->data;q=r;

        r=r->lchild;free(q);

        shorter=1;

         }

    else

    {

                   Delete(q,r->rchild,shorter);

        if(shorter==1)

                            RightBalance_div(r,shorter);

         }

}

 

//平衡二叉树的删除操作

int DeleteAVL(BSTree&p,intx,int&shorter)

{

         intk;

    BSTreeq;

    if(p==NULL)  { printf("不存在要删除的关键字!!\n");return0;}

    else if(x<p->data)//p的左子树中进行删除

    {

                   k=DeleteAVL(p->lchild,x,shorter);

        if(shorter==1)

                            LeftBalance_div(p,shorter);

                   returnk;

         }

         else if(x>p->data)//p的右子树中进行删除

    {

                   k=DeleteAVL(p->rchild,x,shorter);

                   if(shorter==1)

                            RightBalance_div(p,shorter);

                   returnk;

         }

         else

         {

                   q=p;

                   if(p->rchild==NULL)//右子树空则只需重接它的左子树

                   {p=p->lchild;free(q);shorter=1; }

        else if(p->lchild==NULL)//左子树空则只需重接它的右子树

                   {p=p->rchild;free(q);shorter=1; }

        else//左右子树均不空

        {

                            Delete(q,q->lchild,shorter);

                            if(shorter==1)

                                     LeftBalance_div(p,shorter);

                            p=q;

                   }

       return1;

         }

}

 

 

                  

 

 

 

 

 

 

 

 

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

7. 蛤蟆的数据结构进阶七平衡二叉树

标签:

原文地址:http://blog.csdn.net/notbaron/article/details/47324129

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!