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

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)//插入新结点,树“长高”,置taller为true

{

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结点的左子树高,删除结点后p的bf减1,树变矮

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

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

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

else  //p结点的右子树高

{

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

if(p1->bf==0)//p1结点左、右子树等高,删除结点后p的bf为-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;

}

}

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

时间: 2024-10-10 09:51:56

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

5. 蛤蟆的数据结构进阶五动态查询

5. 蛤蟆的数据结构进阶五动态查询 本篇名言:"判断一个人,不是根据他自己的表白或对自己的看法,而是根据他的行动. --列宁" OK,我们接下去来看下动态查询. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47284473 1.  动态查找表 动态查找表:若在查找过程中可以将查找表中不存在的数据元素插入,或者从查找表中删除某个数据元素,则称这类查找表为动态查找表.动态查找表在查找过程中查找表可能会发生变化.对动态

8. 蛤蟆的数据结构进阶八哈希表相关概念

8. 蛤蟆的数据结构进阶八哈希表相关概念 本篇名言:"作家当然必须挣钱才能生活,写作,但是他决不应该为了挣钱而生活,写作.--马克思" 前些笔记我们学习了二叉树相关.现在我们来看下哈希表.这篇先来看下哈希表的相关概念 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47347273 1.  哈希表的概念 哈希表(HashTable)也叫散列表,是根据关键码值(Key Value)而直接进行访问的数据结构.它通过把关键

19. 蛤蟆的数据结构进阶十九外部排序相关概念

19. 蛤蟆的数据结构进阶十九外部排序相关概念 本篇名言:"一个人最怕不老实,青年人最可贵的是老实作风. "老实 " 就是不自欺欺人,做到不欺骗人家容易,不欺骗自己最难. "老实作风 " 就是脚踏实地,不占便宜.世界上没有便宜的事,谁想占便宜水就会吃亏. --徐特立" 之前我们学习的排序都是内部排序的,接下去来看下外部排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47

17. 蛤蟆的数据结构进阶十七排序实现之归并排序

17. 蛤蟆的数据结构进阶十七排序实现之归并排序 本篇名言:"人生不是一种享乐 ,而是一桩十分沉重的工作.-- 列夫 . 托尔斯泰" 我们来看下归并排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47790163 1.  归并排序 归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用.将已有序的子序列合并,得到完全有序的序列:即先使每个

16. 蛤蟆的数据结构进阶十六排序实现之基数排序

16. 蛤蟆的数据结构进阶十六排序实现之基数排序 本篇名言:"社会犹如一条船 ,每人都要有掌舵的准备.--易卜生" 我们来看下基数排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47760601 1.  基数排序 基数排序(radix sort)属于"分配式排序"(distributionsort),又称"桶子法"(bucket sort)或bin sort,顾名思义,

15. 蛤蟆的数据结构进阶十五排序实现之堆排序

15. 蛤蟆的数据结构进阶十五排序实现之堆排序 本篇名言:"谁要是游戏人生 ,他就一事无成 ; 谁不能主宰自己 ,永远是一个奴隶.--歌德" 继续来看下堆排序. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47733553 1.  堆排序 堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一种.可以利用数组的特点快速定位指定索引的元素.堆分为大根堆和小根堆,是完全二叉树

14. 蛤蟆的数据结构进阶十四排序实现之简单选择排序

14. 蛤蟆的数据结构进阶十四排序实现之简单选择排序 本篇名言:"即是我们是一支蜡烛也应该 " 蜡烛成灰泪始干 " 即使我们只是一根火柴也要在关键时刻有一次闪耀即使我们死后尸骨都腐烂了解也要变成磷火在荒野中燃烧. -- 艾青" 继续来看什么是简单选择排序. 欢迎转载,转载请标明出处: 1.  简单选择排序 设所排序序列的记录个数为n.i取1,2,-,n-1,从所有n-i+1个记录(Ri,Ri+1,-,Rn)中找出排序码最小的记录,与第i个记录交换.执行n-1趟后就完

9. 蛤蟆的数据结构进阶九哈希表实现

9. 蛤蟆的数据结构进阶九哈希表实现 本篇名言:"人们所努力追求的庸俗的目标 --我总觉得都是可鄙的. -- 爱因思坦" 上篇我们看了哈希表的相关定义和概念,这篇来看下如何来实现. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47362781 1.  代码实现 1.1             Main 函数定义哈希元素数组 10个元素. 定义哈希表变量. 调用InitHashTable构造一个空的哈希表. 然后循

3. 蛤蟆的数据结构进阶三静态查询之折半查询

3. 蛤蟆的数据结构进阶三静态查询之折半查询 本篇名言:"但是话不行,要紧的是做. --鲁迅" 继续来看静态查询的折半查询. 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/47211637 1.  折半查找 折半查找要求查找表用顺序存储结构存放且各数据元素按关键字有序(升序或隆序)排列,也就是说折半查找只适用于对有序顺序表进行查找. 折半查找的基本思想是:首先以整个查找表作为查找范围,用查找条件中给定值k与中间位置