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

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

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

           我们来看下传说中的平衡二叉树

          

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

 

 

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

typedefstructBSTNode

{

    intdata;

    intbf;                       //结点的平衡因子

    structBSTNode*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的左子树的平衡度,并作相应平衡处理

    {

    caseLH:                //新结点插入在*T的左孩子的左子树上,要作单右旋处理

        T->bf= lc->bf =EH;

       R_Rotate(T); break;

    caseRH:                //新结点插入在*T的左孩子的右子树上,要作双旋处理

        rd =lc->rchild;     //rd指向*T的左孩子的右子树根

        switch(rd->bf)      //修改*T及其左孩子的平衡因子

        {

        caseLH:T->bf=RH; lc->bf =EH;break;

        caseEH:T->bf= lc->bf = EH;break;

        caseRH: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的右子树的平衡度,并作相应平衡处理

    {

    caseRH:               //新结点插入在*T的右孩子的右子树上,要作单左旋处理

        T->bf= rc->bf =EH;

       L_Rotate(T);break;

    caseLH:               //新结点插入在*T的右孩子的左子树上,要作双旋处理

        ld =rc->lchild;    //ld指向*T的右孩子的左子树根

        switch(ld->bf)     //修改*T及其右孩子的平衡因子

        {

        caseLH:T->bf=EH; rc->bf =RH;break;

        caseEH:T->bf= rc->bf =EH;break;

        caseRH: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)returnfalse;

    elseif(EQ(key,T->data))returntrue;

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

    elsereturnSearchBST(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;}

           elseif(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;

        }

                     elseif(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; }

                                elseif(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;}

    elseif(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;

                     }

        elseif(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; }

            elseif(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;}

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

    {

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

        if(shorter==1)

                                LeftBalance_div(p,shorter);

                     returnk;

           }

           elseif(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; }

        elseif(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;

           }

}

 

 

                    

 

 

 

 

 

 

 

 

 

    原文作者:平衡二叉树
    原文地址: https://blog.csdn.net/notbaron/article/details/78067951
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞