博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
AVL树
阅读量:5900 次
发布时间:2019-06-19

本文共 7756 字,大约阅读时间需要 25 分钟。

平衡二叉树,是一个方便查找的树,树的左子树深度与右子树的深度的差总(BF)是在+1,0,-1之中。

随着树的建立,插入,树都会自动的进行调整,使得其满足上面的条件。

1、+1表示左子树的深度比右子树的深度多1.

2、0 表示左子树的深度与右子树的深度相同。

3、-1表示左子树的深度比右子树神的小1.

因此,如果一个数据插入到情况1中,也就是说,数据插入到左子树中,左子树的深度将会比右子树多2.此时,需要调整树的结构。如果插入尾端节点的左子树中,则这个尾端节点相应的BF值,就变成+1.相反,如果插入到它的右子树中,BF值就会变成-1.这个调整也会返回到上面一层的节点,再次进行调整。

 

这里相应的介绍一个左旋,与右旋的基本知识。

比如下图

在进行左旋时,将会发生下面的情况:

void L_Rotate(BiTree *p){    //传入根节点进行右旋    BiTree R;    R = (*p)->rchild;    (*p)->rchild = R->lchild;    R->lchild = (*p);    (*p) = R;}

最后子树将会变成

 

相应的右旋,则运行下面的代码

void R_Rotate(BiTree *p){    //传入一个根节点,进行右旋。定义它的左子树节点为L,根节点的左子树变成L的右子树,L的右子树变成根节点。最后把根节点指针指向L    BiTree L;    L = (*p)->lchild;    (*p)->lchild =  L->rchild;    L->rchild = (*p);    (*p) = L;}

 

了解左旋与右旋后,就该进行树的调整介绍了。

这里有一个技巧:

1 如果插入的元素插入到左子树,使得左子树的BF值发生改变。如果左子树节点的BF值,与根节点的BF值相同符号,则进行一次右旋,即可。但是如果是不同符号,则要进行双旋(即先进性左旋,使得子树高度加一,在进行右旋,平衡子树)

2 如果插入到右子树,也观察符号,相同,则进行一次右旋,如果不同,则进行双旋。

代码如下

void LeftBalance(BiTree *T){    BiTree L,Lr;    L = (*T)->lchild;    switch(L->bf){    case LH://符号与根相同,因此进行右旋一次,就行了        (*T)->bf = L->bf = EH;        R_Rotate(T);        break;    case RH://符号与根不同,要进行双旋;对子树进行一次旋转,再对T进行一次旋转        Lr = L->rchild;        switch(Lr->bf){        case LH: //如果是左子数高,那么对根节点赋值为-1,因为没有右子树,根节点将会出现左子树为空的情况;左子树旋转后,会平衡为EH            (*T)->bf = RH;            L->bf = EH;            break;        case EH://如果为平衡,那么根节点和左子树节点都为平衡EH            (*T)->bf = L->bf = EH;            break;        case RH://如果右子树高,那么对根节点赋值为0,对左子树赋值为+1,因为进行旋转后,左子树节点的右子树会空。根节点EH            (*T)->bf = EH;            L->bf = LH;            break;        }        Lr->bf = EH;        L_Rotate(&(*T)->lchild);        R_Rotate(T);    }}void RightBalance(BiTree *T){    BiTree R,Rl;    R = (*T)->rchild;    switch(R->bf){    case RH:        (*T)->bf = R->bf = EH;        L_Rotate(T);        break;    case LH:        Rl = R->lchild;        switch(Rl->bf){        case LH: //如果是左子数高,那么对根节点赋值为-1,因为没有右子树,根节点将会出现左子树为空的情况;左子树旋转后,会平衡为EH            (*T)->bf = EH;            R->bf = RH;            break;        case EH://如果为平衡,那么根节点和左子树节点都为平衡EH            (*T)->bf = R->bf = EH;            break;        case RH://如果右子树高,那么对根节点赋值为0,对左子树赋值为+1,因为进行旋转后,左子树节点的右子树会空。根节点EH            (*T)->bf = LH;            R->bf = EH;            break;        }        Rl->bf = EH;        R_Rotate(&(*T)->rchild);        L_Rotate(T);    }}

插入时,要遍历到子树的最底层,进行分析,逐层的改变BF值,进行平衡。知道标记taller为0时,表示对深度不发生改变,就不需要向上遍历了。

int insertAVL(BiTree *T,int e, int *taller){    if(!(*T)){        (*T)=(BiTree)malloc(sizeof(BiTNode));        (*T)->data = e;        (*T)->lchild = NULL;        (*T)->rchild = NULL;        (*T)->bf = EH;        *taller = 1;    }else{        if(e == (*T)->data){ //存在相同节点            *taller = 0;            return 0;        }        if(e < (*T)->data){            if(!insertAVL(&(*T)->lchild,e,taller))                return 0;            if(taller){                switch((*T)->bf){                case LH:                    LeftBalance(T);                    *taller = 0;                    break;                case EH:                    (*T)->bf = LH;                    *taller = 1;                    break;                case RH:                    (*T)->bf = EH;                    *taller = 0;                    break;                }            }        }else{            if(!insertAVL(&(*T)->rchild,e,taller))                return 0;            if(taller){                switch((*T)->bf){                case LH:                    (*T)->bf = 0;                    *taller = 0;                    break;                case EH:                    (*T)->bf=RH;                    *taller = 1;                    break;                case RH:                    RightBalance(T);                    *taller = 0;                    break;                }            }        }    }    return 1;}

全部代码:

#include 
#include
#define LH +1#define EH 0#define RH -1typedef struct BiTNode{ int data; int bf; struct BiTNode *lchild,*rchild;}BiTNode,*BiTree;void R_Rotate(BiTree *p);void L_Rotate(BiTree *p);void LeftBalance(BiTree *p);void RightBalance(BiTree *T);int insertAVL(BiTree *T,int e, int *taller);void InOrderTree(BiTree b);int main(){ int i; int a[10]={
4,7,9,1,2,3,0,5,6,8}; BiTree T = NULL; int *taller = (int *)malloc(sizeof(int)); for(i=0;i<10;i++){ insertAVL(&T,a[i],taller); InOrderTree(T); printf("\n"); } getchar();}void InOrderTree(BiTree b){ if( b== NULL) return; InOrderTree(b->lchild); printf("%d ",b->data); InOrderTree(b->rchild);}int insertAVL(BiTree *T,int e, int *taller){ if(!(*T)){ (*T)=(BiTree)malloc(sizeof(BiTNode)); (*T)->data = e; (*T)->lchild = NULL; (*T)->rchild = NULL; (*T)->bf = EH; *taller = 1; }else{ if(e == (*T)->data){ //存在相同节点 *taller = 0; return 0; } if(e < (*T)->data){ if(!insertAVL(&(*T)->lchild,e,taller)) return 0; if(taller){ switch((*T)->bf){ case LH: LeftBalance(T); *taller = 0; break; case EH: (*T)->bf = LH; *taller = 1; break; case RH: (*T)->bf = EH; *taller = 0; break; } } }else{ if(!insertAVL(&(*T)->rchild,e,taller)) return 0; if(taller){ switch((*T)->bf){ case LH: (*T)->bf = 0; *taller = 0; break; case EH: (*T)->bf=RH; *taller = 1; break; case RH: RightBalance(T); *taller = 0; break; } } } } return 1;}void R_Rotate(BiTree *p){ //传入一个根节点,进行右旋。定义它的左子树节点为L,根节点的左子树变成L的右子树,L的右子树变成根节点。最后把根节点指针指向L BiTree L; L = (*p)->lchild; (*p)->lchild = L->rchild; L->rchild = (*p); (*p) = L;}void L_Rotate(BiTree *p){ //传入根节点进行右旋 BiTree R; R = (*p)->rchild; (*p)->rchild = R->lchild; R->lchild = (*p); (*p) = R;}void LeftBalance(BiTree *T){ BiTree L,Lr; L = (*T)->lchild; switch(L->bf){ case LH://符号与根相同,因此进行右旋一次,就行了 (*T)->bf = L->bf = EH; R_Rotate(T); break; case RH://符号与根不同,要进行双旋;对子树进行一次旋转,再对T进行一次旋转 Lr = L->rchild; switch(Lr->bf){ case LH: //如果是左子数高,那么对根节点赋值为-1,因为没有右子树,根节点将会出现左子树为空的情况;左子树旋转后,会平衡为EH (*T)->bf = RH; L->bf = EH; break; case EH://如果为平衡,那么根节点和左子树节点都为平衡EH (*T)->bf = L->bf = EH; break; case RH://如果右子树高,那么对根节点赋值为0,对左子树赋值为+1,因为进行旋转后,左子树节点的右子树会空。根节点EH (*T)->bf = EH; L->bf = LH; break; } Lr->bf = EH; L_Rotate(&(*T)->lchild); R_Rotate(T); }}void RightBalance(BiTree *T){ BiTree R,Rl; R = (*T)->rchild; switch(R->bf){ case RH: (*T)->bf = R->bf = EH; L_Rotate(T); break; case LH: Rl = R->lchild; switch(Rl->bf){ case LH: //如果是左子数高,那么对根节点赋值为-1,因为没有右子树,根节点将会出现左子树为空的情况;左子树旋转后,会平衡为EH (*T)->bf = EH; R->bf = RH; break; case EH://如果为平衡,那么根节点和左子树节点都为平衡EH (*T)->bf = R->bf = EH; break; case RH://如果右子树高,那么对根节点赋值为0,对左子树赋值为+1,因为进行旋转后,左子树节点的右子树会空。根节点EH (*T)->bf = LH; R->bf = EH; break; } Rl->bf = EH; R_Rotate(&(*T)->rchild); L_Rotate(T); }}

运行实例:

 

 

本文转自博客园xingoo的博客,原文链接:,如需转载请自行联系原博主。
你可能感兴趣的文章
【实验报告】实验二:DHCP基本实验
查看>>
Python-OpenCV学习笔记(六)
查看>>
气质的培养(哈佛管理世界)
查看>>
Can&#39;t get Kerberos realm
查看>>
正则表达式 学习笔记1.1
查看>>
通过案例学调优之--AWR BaseLine管理
查看>>
如何使用MySQL提升权限
查看>>
keepalived 原理,安装,配置
查看>>
乐在其中设计模式(C#) - 单例模式(Singleton Pattern)
查看>>
Tensorflow官方语音识别入门教程 | 附Google新语音指令数据集
查看>>
AssetBundle进阶内存优化(Unity 4.x)
查看>>
Windows Home Server 简体中文版安装和配置体验 - 海量图鉴
查看>>
Adobe Reader X:The program used to create this object is AcroExch
查看>>
从九九乘法口决脚本,比较awk、bash/ksh和Perl的循环控制结构[附awk\shell\Perl脚本]...
查看>>
GitHub 版本控制 项目托管 00 总体框架
查看>>
Nginx使用http auth basic认证保护后台admin
查看>>
Be Sociable, Share!
查看>>
SQL Server 实验语句集合一
查看>>
C++中的值传递,引用传递,指针传递
查看>>
使用HVRCapacityPlanner评估Hyper-V副本环境
查看>>