树 -- AVL树
前言
通过之前对二叉查找树的讨论,我们知道在给定节点数目的情况下,二叉树的高度越低,查找所用时间也就越短.
在讨论红黑树的时候,我们说过红黑树并非完全"平衡"的二叉树,只是近似"平衡".那么这个平衡到底指的是什么呢?有没有完全"平衡"的二叉树?
平衡二叉树
什么样的二叉树能被形容为平衡二叉树呢?
1)空树
2)根的左右子树的高度之差的绝对值不超过1,并且左右子树也都是一棵平衡二叉树。
这样的树就被我们认作时平衡二叉树.
显然,当一颗二叉搜索树能够保证上面的性质时,树整体的高度就能得到良好的控制.
二叉树失衡
既然我们已经知道了平衡二叉树的定义,并且了解到了它的诸多好处.那么如何将一颗二叉搜索树构建成平衡二叉搜索树呢? (我们首先约定,叶子节点的高度为1.NULL节点的高度为0.)
首先让我们分析一下插入和删除操作中,二叉搜索树"失衡"后的状态.如下图所示:

我们在2的左边插入了新的节点3后,使得对于1来讲,其左子树高度为2,右子树高度为1.进入了失衡的状态.
概括的讲,如果将平衡二叉树上某个节点的较高子树(比另一颗子树的高度大1)再增加1的高度,或者将某个节点的较低子树(比另一颗子树的高度小1)再减小1的高度,就会产生二叉树的失衡.
下面列举一下失衡的状态.
--泛型>
因为是1左侧的左侧的节点造成的失衡,所以称为LL失衡.
--泛型>
与LL失衡对称的RR失衡.
--泛型>
因为是1左侧的右侧的节点造成的失衡,所以成为LR失衡.
--泛型>
与LR失衡对称的RL失衡.
失衡二叉树的恢复操作
在红黑树中,我们对于失衡的调整是根据节点的颜色,进行旋转和赋值操作来保证一种"近似的平衡".
那么对于一颗要保证"平衡的"的二叉树,该如何调整呢?我们分情况讨论一下.
1)LL失衡与LR失衡
对于某处的LL失衡,需要进行右旋操作,化解此处的失衡.然后向上查看是否还存在其他类型的失衡.

对于RR失衡的修正类似于LL失衡的处理,旋转的方向改变成了左旋.
template<class T>
TNode<T>* AvlTree<T>::__leftleftRotate(TNode<T> *dest){
assert(dest!=nil || dest->left!=nil); TNode<T> *l = dest->left;
dest->left = l->right;
l->right = dest; dest->height = __maxHeight(dest->left,dest->right)+;
l->height = __maxHeight(l->left,l->right)+; if(root == dest)
root = l;
return l;
}
template<class T>
TNode<T>* AvlTree<T>::__rightrightRotate(TNode<T> *dest){
assert(dest!= || dest->right!=); TNode<T> *r = dest->right;
dest->right = r->left;//Between dest and new left
r->left = dest; dest->height = __maxHeight(dest->left,dest->right)+;
r->height = __maxHeight(r->left,r->right)+; if(root == dest)
root = r;
return r;
}
2) 对于LR失衡和RL失衡
对于LR失衡,我们需要先对2节点进行左旋操作,然后对1节点进行右旋操作.这样可以将1节点下的不平衡消除.之后需要向上查看是否有其他不平衡节点.

对于RL失衡的处理,与LR类似.
template<class T>
TNode<T>* AvlTree<T>::__leftrightRotate(TNode<T> *dest){
__rightrightRotate(dest->left);
return __leftleftRotate(dest);
}
template<class T>
TNode<T>* AvlTree<T>::__rightleftRotate(TNode<T> *dest){
__leftleftRotate(dest->right);
return __rightrightRotate(dest);
}
插入
能破坏一课平衡二叉树的操作为插入新节点,和删除已有节点.我们结合前面讲的平衡恢复方法来实现平衡二叉树的插入操作.
插入某个节点之后,可能会破坏插入所经过的路径上的节点的平衡度.所以需要回溯路径上节点当前的平衡性.这种场合十分适合递归的方法.
template<class T>
TNode<T>* AvlTree<T>::__insert(T val,TNode<T> *curr){
if(curr==nil){
TNode<T> *in = new TNode<T>(val,nil,nil,);
assert(in);
if(nil == root)
root = in;
curr = in;
}else if(curr->val > val){
curr->left = __insert(val,curr->left);
if(std::abs(height(curr->left)-height(curr->right))>){
if(val < curr->left->val){
curr = __leftleftRotate(curr);
}else{
curr = __leftrightRotate(curr);
}
}
}else if(curr->val < val){
curr->right = __insert(val,curr->right);
if(std::abs(height(curr->left)-height(curr->right))>){
if(val > curr->right->val){
curr = __rightrightRotate(curr);
}else{
curr = __rightleftRotate(curr);
}
}
}else{
std::cout<<"Duplicate val !\n"<<std::endl;
assert();
}
curr->height = __maxHeight(curr->left,curr->right) + ;
return curr;
}
删除
产出某个节点后带来的失衡就类似于在另一支上插入了一个节点而带来的失衡.
依然需要回溯路径上的节点.
template<class T>
TNode<T>* AvlTree<T>::__erase(TNode<T> *dest,TNode<T> *currRoot){
assert(dest); if(currRoot->val > dest->val){
currRoot->left = __erase(dest,currRoot->left); if(std::abs(height(currRoot->left)-height(currRoot->right))>){
if(height(currRoot->right->right) > height(currRoot->right->left))
currRoot = __rightrightRotate(currRoot);
else
currRoot = __rightleftRotate(currRoot);
}
}else if(currRoot->val < dest->val){
currRoot->right = __erase(dest,currRoot->right);
if(std::abs(height(currRoot->left)-height(currRoot->right)>)){
if(height(currRoot->left->left) > height(currRoot->left->right))
currRoot = __leftleftRotate(currRoot);
else
currRoot = __leftrightRotate(currRoot);
}
}else{//currRoot->val == dest->val
TNode<T> *replace;
if(currRoot->left!=nil && currRoot->right!=nil){
if(height(currRoot->left) > height(currRoot->right)){
replace = predecessor(currRoot);
currRoot->val = replace->val;
currRoot->left = __erase(replace,currRoot->left);
}else{
replace = successor(currRoot);
currRoot->val = replace->val;
currRoot->right = __erase(replace,currRoot->right);
}
}else{
replace = (currRoot->left!=nil)?currRoot->left:currRoot->right;
delete dest;
currRoot = replace;
}
}
currRoot->height = ((currRoot==nil)?:__maxHeight(currRoot->left,currRoot->right)+);
return currRoot;
}
参考
http://www.cnblogs.com/skywang12345/p/3603935.html
树 -- AVL树的更多相关文章
- 树·AVL树/平衡二叉树
1.AVL树 带有平衡条件的二叉查找树,所以它必须满足条件: 1 是一棵二叉查找树 2 满足平衡条件 1.1 平衡条件: 1)严格的平衡条件:每个节点都必须有相同高度的左子树和右子树(过于严格而不被使 ...
- 04-树4. Root of AVL Tree-平衡查找树AVL树的实现
对于一棵普通的二叉查找树而言,在进行多次的插入或删除后,容易让树失去平衡,导致树的深度不是O(logN),而接近O(N),这样将大大减少对树的查找效率.一种解决办法就是要有一个称为平衡的附加的结构条件 ...
- 红黑树/B+树/AVL树
RB Tree 红黑树 :http://blog.csdn.net/very_2/article/details/5722682 Nginx的RBTree实现 :http://blog.csdn ...
- 数据结构--树--AVL树
详情查看:http://www.cnblogs.com/skywang12345/p/3577360.html
- 纸上谈兵:AVL树
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 二叉搜索树的深度与搜索效率 我们在树, 二叉树, 二叉搜索树中提到,一个有n个节点 ...
- 平衡搜索树(一) AVL树
AVL树 AVL树又称为高度平衡的二叉搜索树,是1962年有俄罗斯的数学家G.M.Adel'son-Vel'skii和E.M.Landis提出来的.它能保持二叉树的高度 平衡,尽量降低二叉树的高度,减 ...
- 红黑树和AVL树的实现与比较-----算法导论
一.问题描述 实现3种树中的两种:红黑树,AVL树,Treap树 二.算法原理 (1)红黑树 红黑树是一种二叉查找树,但在每个结点上增加一个存储位表示结点的颜色,可以是red或black.红黑树满足以 ...
- 二叉树,AVL树和红黑树
为了接下来能更好的学习TreeMap和TreeSet,讲解一下二叉树,AVL树和红黑树. 1. 二叉查找树 2. AVL树 2.1. 树旋转 2.1.1. 左旋和右旋 2.1.2. 左左,右右,左右, ...
- 纸上谈兵: AVL树[转]
作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 二叉搜索树的深度与搜索效率 我们在树, 二叉树, 二叉搜索树中提到,一个有n个节点 ...
随机推荐
- mysql的面试试题
1, mysql的复制原理以及流程. (1)先问基本原理流程,3个线程以及之间的关联. 答:Mysql复制的三个线程:主库线程,从库I/O线程,从库sql线程: 复制流程:(1)I/O线程向主库发出请 ...
- JeeSite 企业信息化快速开发平台
平台简介 JeeSite是基于多个优秀的开源项目,高度整合封装而成的高效,高性能,强安全性的开源Java EE快速开发平台. JeeSite本身是以Spring Framework为核心容器,Spri ...
- 从头开始-05.C语言中函数
函数: 完成特定功能代码段 特点:函数只有调用的时候才会执行 定义格式:返回值类型 函数名称(形参类型 形参名称,...){ 语句; ... } 函数参数 形式参数:在定义函数的时候,函数名后面小括 ...
- css overflow
overflow-x,overflow-y的值相同等同于overflow overflow-x,overflow-y的值不同,其中一个被赋值visible,另一个被赋值为auto,scroll,hid ...
- java中获取类加载路径和项目根路径的5种方法
import java.io.File; import java.io.IOException; import java.net.URL; public class MyUrlDemo { publi ...
- satellite-menu和ArcMenu
github上的开源库其实还是很不错的,之前的时候总感觉学一些开源库比较麻烦,里边有好多方法什么的,今天终于迈出了第一步,中间也遇到了一些问题,现在总结下,也给其他刚开始学习开源库的小伙伴一些指导: ...
- dom 删除和清除
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...
- mysql数据库sql优化
此文章为转载 一. 前提 这里的原则 只是针对mysql数据库,其他的数据库 某些是殊途同归,某些还是存在差异.我总结的也是mysql普遍的规则,对于某些特殊情况得特殊对待.在构造sql语句的时候养成 ...
- 安装程序时出现错误代码0x80070422
通过win10应用商店,下载应用,安装时出现错误代码0x80070422. 需要打开services.msc,将windows update服务打开.
- Oracle EBS-SQL (PO-4):检查采购订单明细.sql
SELECT PHA.SEGMENT1 订单号, pha.approved_flag 批准状态, pha.closed_code 订 ...