树 -- 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个节点 ...
随机推荐
- 安装Linux系统到u盘
第一步:首先插入u盘到电脑主机usb接口处(建议插入到主机箱后置的usb接口).然后打开UltraISO软件,再打开选择须要写入u盘的Ubuntu 10.04或者其它版本号的Linux系统的iso镜像 ...
- asp.netGridView使用技巧
GridView属性介绍 AutoGenerateColumns 如果为true表示自动生成数据列,如果为false关闭自动生成状态 何为自动生成数据列 比如这么一个表格: country name ...
- sublime安装和汉化
对程序员来说,在不同的平台下有不同的IDE,网上很多教程都是使用DW,以致DW大名鼎鼎.其实,还有一些我们不为熟知的,却超级牛X的编辑器,我相信Sublime Text就是其中之一. 官方下载地址:h ...
- javascript模式——Facade
Facade模式为许多代码提供一个方便的接口,不现实代码实现的复杂性,这样,使用者只需要关心他的使用接口就可以使用. 下面来看一段Facade模式的运用,绑定事件在浏览器之间是不一样的,利用Facad ...
- Sublime 学习记录(一) Sublime 的快捷键
Ctrl + Shift + P : 打开命令面板 Ctrl + P : 搜索项目中的文件 Ctrl + W : 关闭当前打开的文件 Ctrl + G : 跳转到第几行 Ctrl + Shift + ...
- UVA 1312 Cricket Field
题意: 在w*h的坐标上给n个点, 然后求一个最大的矩形,使得这个矩形内(不包括边界)没有点,注意边界上是可以有点的. 分析: 把坐标离散化.通过两重循环求矩形的高,然后枚举,看是否能找到对应的矩形. ...
- 设计模式之UML类图
在学设计模式的过程中经常碰到各式各样的UML类图.那些眼花缭乱的符号有什么含义呢? 类图含义 类图中的关系 从网上找来一张图作为实例 依赖关系:比如动物依赖氧气和水,这里如学生要依赖自行车.用虚线箭头 ...
- mysql优化(3) 集群配置
两台服务器 192.168.187.131 192.168.187.132 1.主从配置 131为主 132为从 在131下 vim /etc/my.cnf [mysqld] datadir=/var ...
- PTF在PET上印刷線路的注意事項
PTF: Polymer Thick Film (聚合厚模),維基的解釋 PET: Polyethylene terephthalate (聚乙烯對苯二甲酸酯),維基的解釋 就如同大家所知道的,相較於 ...
- Matlab.NET混编技巧之——找出Matlab内置函数
原文 http://www.cnblogs.com/asxinyu/p/3295309.html Matlab与.NET的混合编程,掌握了基本过程,加上一定的开发经验和算法基础,肯 定不难.反之,有时 ...