数据结构之平衡二叉树(AVL树)
平衡二叉树(AVL树)定义如下:平衡二叉树或者是一棵空树,或者是具有以下性质的二叉排序树:
(1)它的左子树和右子树的高度之差绝对值不超过1;
(2)它的左子树和右子树都是平衡二叉树。
AVL树避免了平衡二叉树初始序列有序建立的类似单链表情况,提高了查找效率。
1.AVL树的相关参量定义
#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#define DataType int
#define LH 1 //左边高一层
#define EH 0 //左右分支等高
#define RH -1 //右边高一层
const int MAXSIZE = 100;//栈和队列的最大容量
typedef struct BSTNode{
DataType data;
int bf;//平衡因子,值为LH、EH、RH
struct BSTNode *lchild, *rchild;
}BSTNode, *BSTree;
2.插入函数
bool InsertAVL(BSTree &T,DataType x,boolean &taller)//插入后是否长高,一处修改处处修改,taller为bool类型
{//插入过程伴随着查找过程,没有则插入
if (!T)//如果空树,则直接添加新结点
{
T = (BSTree)malloc(sizeof(BSTNode));
T->data = x;
T->lchild = T->rchild = NULL;
T->bf = EH;
taller = true;//长高了
}
else
{
if (T->data == x)//数据元素已存在,不必插入
{
taller = false;
return false;
}
else if (x < T->data)//数据在树根的左分支
{
if (!InsertAVL(T->lchild, x, taller))//左分支已存在,但即使不存在也返回了taller的值
return false;
if (taller)//如果导致树长高了,则进一步判断及处理
{
switch (T->bf)
{
case LH://左分支本来就比右分支高一层,又加了一层,当然进行左平衡
LeftBalence(T);//左调平衡函数
taller = false;
break;
case EH://本来左右等高,修改标志位即可
T->bf = LH;
taller = true;
break;
case RH://本来右分支高1,修改标志位
T->bf = EH;
taller = false;
break;
}
}
}
else
{
if (!InsertAVL(T->rchild, x, taller))//进行T的右分支,同理
return false;
if (taller)
{
switch (T->bf)
{
case RH:
RightBalence(T);
taller = false;
break;
case EH:
T->bf = RH;
taller = true;
break;
case LH:
T->bf = EH;
taller = false;
break;
}
}
}
}
return true;
}
3.着重分析左右调平衡函数
左调平衡
有且仅有两种情况,一定是原本左边比右边高1层,而且在左边加了1层才要左调平衡的。
(1)

这种情况是在原本的根节点T的左孩子L上加了左孩子,显然此时T和L都无右孩子,所以要调整为L为根节点,也就是T根节点右旋(顺时针旋转)。
调整完显然平衡因子bf变化为 T->bf = L->bf = EH;
(2)另一种是在原本的根节点T的左孩子L上加了右孩子导致失衡(某一结点的做右分支高度相差大于1)产生。
(A)



对应(1)的情况,在L加了右孩子Lr,且L无左孩子,T无右孩子。先将L左旋(L逆时针旋转)得到类似(1)的情形,然后将T右旋。
调整完三个结点平衡因子 T->bf = L->bf =Lr->bf= EH;
(B)此种情况为在L的右孩子Lr上加了左孩子



先将L左旋,Lr作为L的双亲结点T的左孩子,L作为Lr的左孩子,Lr的左孩子作为L的右孩子,这也是具体的左旋算法,然后将T右旋。
调整完三个结点平衡因子 T->bf = RH; L->bf = EH; Lr->bf = EH;
(C)此种情况为在L的右孩子Lr上加了右孩子





先将L左旋,然后将T作为Lr的右孩子,且将Lr的右孩子最为T的左孩子,这也是具体的右旋算法。
调整完三个结点平衡因子 T->bf = EH; L->bf = LH; Lr->bf = EH;
注意,此调平衡的规则的代码是递归式的,所以一定是从底层往上层调平衡,也就是说下面先调平衡。
总结(2):具体的也分析了左旋右旋的具体算法,每种情况都有Lr->bf=EH,并且算法都符合平衡二叉树的规则要求。
void R_Rotate(BSTree &T)//右旋,T的左孩子可能有右孩子或者为空,一起整
{
BSTree p;
p = T->lchild;
T->lchild = p->rchild;
p->rchild = T;
T=p;
}
void L_Rotate(BSTree &T)//左旋
{
BSTree p;
p = T->rchild;
T->rchild = p->lchild;
p->lchild = T;
T = p;
}
void LeftBalence(BSTree &T)//平衡左分支
{
BSTree L, Lr;
L = T->lchild;
switch (L->bf)
{
case LH://是在根节点T的左孩子L的左孩子上加了结点导致失衡
T->bf = L->bf = EH;//调整后的参数变化
R_Rotate(T);//右旋根节点T
break;
case RH://是在根节点T的左孩子L的左孩子上加了结点导致失衡
Lr = L->rchild;
switch (Lr->bf)//对L的右孩子Lr的参数bf进行判断及进一步分析
{
case LH://Lr的左边加了新结点
T->bf = RH;
L->bf = EH;
break;
case EH://Lr左右等高
T->bf = L->bf = EH;
break;
case RH://Lr的右边边加了新结点
T->bf = EH;
L->bf = LH;
break;
}
//统一改参数,先左旋T的左孩子,再右旋T
Lr->bf = EH;
L_Rotate(T->lchild);
R_Rotate(T);
}
}
右调平衡与左调平衡类似的分析方法。
void RightBalence(BSTree &T)//平衡右分支
{
BSTree 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 RH:
T->bf = LH;
R->bf = EH;
break;
case EH:
T->bf = R->bf = EH;
break;
case LH:
T->bf = EH;
R->bf = RH;
break;
}
Rl->bf = EH;
R_Rotate(T->rchild);
L_Rotate(T);
}
}
4.创建函数及其他函数
void CreatAVL(BSTree &T,int n)//创建AVL树,用到了插入函数
{
printf("请输入%d个数据:\n", n);
int a;
boolean taller = 0;//初始化
for (int i = 0; i < n; i++)//循环添加
{
scanf("%d", &a);
InsertAVL(T, a,taller);
}
}
void InOrder(BSTree &T)//中序遍历看是否是递增序列
{
if (T)
{
InOrder(T->lchild);
printf("%3d", T->data);
InOrder(T->rchild);
}
}
void TreeDispNode(BSTree bt)//括号表示法,用来看树的构造情况
{
if (bt != NULL)
{
printf("%d", bt->data);
if (bt->lchild != NULL || bt->rchild != NULL)
{
printf("(");
TreeDispNode(bt->lchild);
if (bt->rchild != NULL)printf(",");
TreeDispNode(bt->rchild);
printf(")");
}
}
}
5.测试代码
int main()//测试代码
{
BSTree mytree=NULL;
CreatAVL(mytree, 10);
InOrder(mytree);
printf("\n");
TreeDispNode(mytree);
printf("\n");
system("pause");
return 0;
}
注意:代码的相关函数要调整位置,使得被调用的函数在调用其的函数之前,分析调整代码应数形结合。
数据结构之平衡二叉树(AVL树)的更多相关文章
- 【数据结构】平衡二叉树—AVL树
(百度百科)在计算机科学中,AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.查找.插入和删除在平均和最坏情况下都是O(log n).增 ...
- 二叉查找树(BST)、平衡二叉树(AVL树)(只有插入说明)
二叉查找树(BST).平衡二叉树(AVL树)(只有插入说明) 二叉查找树(BST) 特殊的二叉树,又称为排序二叉树.二叉搜索树.二叉排序树. 二叉查找树实际上是数据域有序的二叉树,即对树上的每个结点, ...
- 数据结构与算法——AVL树类的C++实现
关于AVL树的简单介绍能够參考:数据结构与算法--AVL树简单介绍 关于二叉搜索树(也称为二叉查找树)能够參考:数据结构与算法--二叉查找树类的C++实现 AVL-tree是一个"加上了额外 ...
- Java 树结构实际应用 四(平衡二叉树/AVL树)
平衡二叉树(AVL 树) 1 看一个案例(说明二叉排序树可能的问题) 给你一个数列{1,2,3,4,5,6},要求创建一颗二叉排序树(BST), 并分析问题所在. 左边 BST 存在的问题分析: ...
- 平衡二叉树,AVL树之图解篇
学习过了二叉查找树,想必大家有遇到一个问题.例如,将一个数组{1,2,3,4}依次插入树的时候,形成了图1的情况.有建立树与没建立树对于数据的增删查改已经没有了任何帮助,反而增添了维护的成本.而只有建 ...
- 数据结构(三)实现AVL树
AVL树的定义 一种自平衡二叉查找树,中面向内存的数据结构. 二叉搜索树T为AVL树的满足条件为: T是空树 T若不是空树,则TL.TR都是AVL树,且|HL-HR| <= 1 (节点的左子树高 ...
- 二叉查找树(BST)、平衡二叉树(AVL树)
二叉查找树(BST) 特殊的二叉树,又称为排序二叉树.二叉搜索树.二叉排序树. 二叉查找树实际上是数据域有序的二叉树,即对树上的每个结点,都满足其左子树上所有结点的数据域均小于或等于根结点的数据域,右 ...
- 图解:平衡二叉树,AVL树
学习过了二叉查找树,想必大家有遇到一个问题.例如,将一个数组{1,2,3,4}依次插入树的时候,形成了图1的情况.有建立树与没建立树对于数据的增删查改已经没有了任何帮助,反而增添了维护的成本.而只有建 ...
- 数据结构与算法分析-AVL树
1.AVL树是带有平衡条件的二叉查找树. 2.AVL树的每个节点高度最多相差1. 3.AVL树实现的难点在于插入或删除操作.由于插入和删除都有可能破坏AVL树高度最多相差1的特性,所以当特性被破坏时需 ...
- 数据结构——二叉查找树、AVL树
二叉查找树:由于二叉查找树建树的过程即为插入的过程,所以其中序遍历一定为升序排列! 插入:直接插入,插入后一定为根节点 查找:直接查找 删除:叶子节点直接删除,有一个孩子的节点删除后将孩子节点接入到父 ...
随机推荐
- 为何JAVA虚函数(虚方法)会造成父类可以"访问"子类的假象?
首先,来看一个简单的JAVA类,Base. 1 public class Base { 2 String str = "Base string"; 3 protected vo ...
- Ubuntu下的MySQL安装
<1>安装mysql-server sudo apt-get update sudo apt-get install mysql-server mysql-client <2> ...
- CSS line-height与vertical-align:baseline
一.当line-height与vertical-align相遇,会发生很多匪夷所思的现象 首先,请看如下代码: <!DOCTYPE html> <html> <head& ...
- mac系统小记
1.设置 ls 命令结果的颜色 默认的 ls 是没有颜色的,可以通过设置 CLICOLOR 和 LSCOLORS 两个环境变量来实现.其中,CLICOLOR 是用来设置是否进行颜色的显示(CLI: ...
- Excel—身份证生日提取
一.只有18位的身份证号码 如: 身份证号 330682199302264000 41120019890823729X 231081199002256839 131101198203154666 36 ...
- PropertiesFactoryBean PropertyPlaceholderConfigurer 区别
正如 stackoverflow上说的,PropertiesFactoryBean 是PropertiesLoaderSupport 直接的实现类, 专门用来管理properties文件的工厂bean ...
- 微信公共服务平台开发(.Net 的实现)12-------网页授权(上 :更加深入理解OAuth2.0 )
我们首先来认识一下OAuth协议吧,这个东西很早就听说过,总觉得离我很远(我的项目用不到这些),但是最近不得不学习一下了.我在网上找了一些解释,认为解释的最好的是这样说的(出处:http://hi.b ...
- sqlserver 自增ID插入指定数据
set identity_insert 表名 ON --允许对自增列Id插入指定数据 insert into table_name(Id,Name) values(1,'test') set iden ...
- 《C++ 101条建议》学习笔记——第一章快速入门
1.C++程序组成:a.编译指示,由#开始,不由分号结束.只是影响编译过程.b.声明语句,影响编译过程,编译结果中并不会生成对应的指令.只是告诉编译器一些信息.c.可执行过程语句,生成对应的指令.包括 ...
- C#高级编程笔记 Day 4, 2016年9月 12日(接口)
1.定义和实现接口:接口名称通常上以字母 I 开头 例子:定义IBankAccount接口 namespace Test.YinXi{ public interface IBankAccount{ v ...