[树结构]平衡二叉树AVL
平衡二叉树是一种二叉排序树,其中每一个节点的左子树和右子树的高度至多等于1,平衡二叉树又称为AVL树。
将二叉树节点的左子树深度减去右子树深度的值称为平衡因子BF,平衡二叉树上所有节点的平衡因子只可能是-1,0或者1。
距离插入点最近的,且平衡因子的绝对值大于1的结点为根的子树,我们称为最小不平衡子树。

平衡二叉树实现原理
先来看一个例子:
对于数组a[10]={3,2,1,4,5,6,7,10,9,8}构建平衡二叉树。
按照二叉排序树的方式插入新的元素,当插入1的时候,使得当前二叉树失去平衡:

当插入5的时候,使得平衡二叉树再次失去平衡:

插入6的时候,同样产生不平衡:

注意:上面的这些不平衡都有一个共同的特点,那就是最小不平衡子树的根的BF同它的孩子(左孩子或者右孩子)的BF是同号的。所以这是仅需要一次旋转就可以了。
当插入到数字9的时候,同样的发生了不平衡:

从上面的图可以看到一次的旋转是不能做到再次的平衡的。所以要两次旋转。


在插入8的时候,同样的发生了不平衡,同样的需要两次调整:



所以总结上面的过程:
当最小不平衡子树根节点的平衡因子BF是大于1的时候,就右旋,小于-1时就左旋。
插入节点后,最小不平衡子树的BF与它的子树的BF符号相反时,就需要对子树节点先进行一次旋转,以使得符号相同后,在反向旋转一次才能够完成平衡操作。
平衡二叉树算法实现
加入了平衡因子,所以在每一个结点中增加一个数据域,这个数据域表示以这个结点为根的二叉树的平衡因子。所以树结点的定义为:
typedef struct BiTNode
{
int data;
int bf;
struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;
其实对于二叉平衡树的每一次的调整都可以分成两个步骤:
- 调整各个结点的BF值
- 旋转子树结构
先写旋转子树结构代码:
void R_Rotate(BiTree *T)
{
BiTree tmp;
tmp = (*T)->lchild;
(*T)->lchild = tmp->rchild;
tmp->rchild = (*T);
*T = tmp;
} void L_Rotate(BiTree *T)
{
BiTree tmp;
tmp = (*T)->rchild;
(*T)->rchild = tmp->lchild;
tmp->lchild = (*T);
*T = tmp;
}
所以当插入一个新的结点,导致树结构不平衡的时候,当树右边超重的时候,要右平衡:(树主体左旋转)
//右平衡,右子树超重
void RightBalance(BiTree *T)
{
BiTree tmp, tmpr;
tmp = (*T)->rchild;
switch (tmp->bf)
{
case -1:
(*T)->bf = 0;
tmp->bf = 0;
L_Rotate(T);
break;
case 1:
tmpr = tmp->lchild;
switch (tmpr->bf)
{
case 1:
tmp->bf = -1;
(*T)->bf = 0;
break;
case -1:
tmp->bf = 0;
(*T)->bf = 1;
break;
case 0:
tmp->bf = (*T)->bf = 0;
} tmpr->bf = 0;
//R_Rotate(&tmp);是错误的,因为不能修改上一级的指针
R_Rotate(&(*T)->rchild);
L_Rotate(T);
}
}
当插入一个结点导致树结构不平衡的时候,左子树超重,要左平衡:(树主体右旋转)
//左平衡,左子树超重
void LeftBlance(BiTree *T)
{
BiTree tmp,tmpr;
tmp = (*T)->lchild;
switch (tmp->bf)
{
case 1:
(*T)->bf = 0;
tmp->bf = 0;
R_Rotate(T);
break;
case -1:
tmpr = tmp->rchild;
switch (tmpr->bf)
{
case 1:
tmp->bf = 0;
(*T)->bf = -1;
break;
case -1:
tmp->bf = 1;
(*T)->bf = 0;
break;
case 0:
(*T)->bf = 0;
tmp->bf = 0;
break;
}//switch tmpr->bf = 0;
//L_Rotate(&tmp);是错误的,因为不能修改上一级的指针
L_Rotate(&(*T)->lchild);
R_Rotate(T);
}
}
注意:上面两处的双旋转的时候,不能旋转tmp,因为这样不能把父结点的指针修改,所以要旋转父结点指下来得指针。
最后插入操作的主函数:
bool InsertAVL(BiTree *T, int key, bool *taller)
{
if (*T ==NULL)
{
*T = (BiTree)malloc(sizeof(BiTNode));
(*T)->data = key;
(*T)->lchild = (*T)->rchild = NULL;
(*T)->bf = 0;
*taller = true; return true;
} if((*T)->data == key)
{
*taller = false;
return false;
}
else if((*T)->data > key)
{
if(!InsertAVL(&(*T)->lchild, key, taller))
return false;
if(*taller)
{
switch ((*T)->bf)
{
case 1:
LeftBlance(T);
*taller = false;
break;
case 0:
(*T)->bf = 1;
*taller = true;
break;
case -1:
(*T)->bf = 0;
*taller = false;
break;
}//switch
}//if
}//else if
else //(*T)->data < key
{
if (!InsertAVL(&(*T)->rchild, key, taller))
return false;
if(*taller)
{
switch ((*T)->bf)
{
case 1:
(*T)->bf = 0;
*taller = false;
break;
case 0:
(*T)->bf = -1;
*taller = true;
break;
case -1:
RightBalance(T);
*taller = false;
}//switch
}//if
}//else return true;
}
[树结构]平衡二叉树AVL的更多相关文章
- Java 树结构实际应用 四(平衡二叉树/AVL树)
平衡二叉树(AVL 树) 1 看一个案例(说明二叉排序树可能的问题) 给你一个数列{1,2,3,4,5,6},要求创建一颗二叉排序树(BST), 并分析问题所在. 左边 BST 存在的问题分析: ...
- 二叉查找树、平衡二叉树(AVL)、B+树、联合索引
1. [定义] 二叉排序树(二拆查找树)中,左子树都比节点小,右子树都比节点大,递归定义. [性能] 二叉排序树的性能取决于二叉树的层数 最好的情况是 O(logn),存在于完全二叉排序树情况下,其访 ...
- 数据结构与算法--从平衡二叉树(AVL)到红黑树
数据结构与算法--从平衡二叉树(AVL)到红黑树 上节学习了二叉查找树.算法的性能取决于树的形状,而树的形状取决于插入键的顺序.在最好的情况下,n个结点的树是完全平衡的,如下图"最好情况&q ...
- 二叉查找树(BST)、平衡二叉树(AVL树)(只有插入说明)
二叉查找树(BST).平衡二叉树(AVL树)(只有插入说明) 二叉查找树(BST) 特殊的二叉树,又称为排序二叉树.二叉搜索树.二叉排序树. 二叉查找树实际上是数据域有序的二叉树,即对树上的每个结点, ...
- 平衡二叉树AVL - 插入节点后旋转方法分析
平衡二叉树 AVL( 发明者为Adel'son-Vel'skii 和 Landis)是一种二叉排序树,其中每一个节点的左子树和右子树的高度差至多等于1. 首先我们知道,当插入一个节点,从此插入点到树根 ...
- 平衡二叉树(AVL)介绍及其实现
一.平衡二叉树 任何一个数据的查找过程都需要从根结点出发,沿某一个路径朝叶子结点前进.因此查找中数据比较次数与树的形态密切相关. 对于二叉树来说,当树中每个结点左右子树高度大致相同时,树高为logN. ...
- 平衡二叉树(AVL)的理解和实现(Java)
AVL的定义 平衡二叉树:是一种特殊的二叉排序树,其中每一个节点的左子树和右子树的高度差至多等于1.从平衡二叉树的名字中可以看出来,它是一种高度平衡的二叉排序树.那么什么叫做高度平衡呢?意思就是要么它 ...
- 转载:平衡二叉树(AVL Tree)
平衡二叉树(AVL Tree) 转载至:https://www.cnblogs.com/jielongAI/p/9565776.html 在学习算法的过程中,二叉平衡树是一定会碰到的,这篇博文尽可能简 ...
- 【数据结构】平衡二叉树—AVL树
(百度百科)在计算机科学中,AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.查找.插入和删除在平均和最坏情况下都是O(log n).增 ...
随机推荐
- XSD (xml Schema Definition)
.xsd文件是定义DataSet的XML文件,利用XML文件的结构优势容易可视化地设计DataSet,设计完它会生成相应的.cs文件,里面的内容就是对应的类型化的DataSet.你的代码里的DataA ...
- 解决 Boot Camp 虚拟机升级到 Windows 10 后 Parallels Desktop 不能识别的问题
最近几天 Win10 正式版开始推送了,对于喜欢折腾的博主,在第一时间就把 Mac 中 Boot Camp 从 Win7 升级到 Win10,初步体验还不错,等博主用过一段时间之后,再来给大家分享使用 ...
- Mvc5+Entity Framework6 之二----在MVC中用Entity Framework实现基本的CRUD
目标:创建控制器和视图的代码,实现CRUD(创建,读取,更新,删除)功能 创建一个详细信息页 控制器为Students的Index页生成的代码排除Enrollments属性在外,因为该属性中关联着一个 ...
- iOS各种类
http://www.isenhao.com/xueke/jisuanji/bcyy/objc.php http://www.code4app.com 这网站不错,收集各种 iOS App 开发可以用 ...
- Java和PHP在Web开发方面的比较
比较 PHP和JSP这两个Web开发技术,在目前的情况是其实是比较PHP和Java的Web开发.以下是我就几个主要方面进行的比较: 一. 语言比较 PHP是解释执行的服务器脚本语言,首先php有简单容 ...
- 对FineU框架Grid多表头合计行导出Excel的回顾
年前用FineUI开发遇到了这样一个问题,Grid多表头合计行不能导出,后面到官方示例找了一下,庆幸的是找到了多表头的导出示例.然后当时为了省事,直接就复制粘贴完事,也没有仔细的研究代码.后来运行一看 ...
- 前端公共库cdn服务推荐//提高加载速度/节省流量
前端公共库cdn服务推荐,使用可以提高js库加载速度同时也可以节省自己空间的流量,CDN加速公共库虽好,不过一定要使用靠谱的前端cdn服务提供方. 以下整理出比较靠谱的国内cdn加速服务器.排名不分先 ...
- winform使用xml作为数据源
1.新建窗体应用程序 2.拖放DataGridView 3.在bin\Debug中放入XML文件 using System; using System.Collections.Generic; usi ...
- new关键字和newInstance()方法的区别
转载:http://blog.csdn.net/iloveyin/article/details/7965183 1.类的加载方式不同 在执行Class.forName("a.clas ...
- python学习笔记:python序列
python序列包括字符串.列表和元组三部分,下面先总的说一下python序列共有的一些操作符和内建函数. 一.python序列 序列类型操作符 标准类型的操作符一般都能适用于所有的序列类型,这里说一 ...