我的新发现:AVL树旋转的一个特性
关于AVL树旋转的代码网络上铺天盖地。
一些经典的实现方法如下:
AVLTree SingleLeftRotation(AVLTree A)
{
AVLTree B = A->left;
A->Left = B->Right;
B->Right = A;
A->Height = Max(GetHeight(A->Left), GetHeight(A->Right)) + ;
B->Height = Max(GetHeight(B->Left), A->Height) + ; return B;
} AVLTree DoubleLeftRightRotation(AVLTree A)
{
A->Left = SingleRightRotation(A->Left); return SingleLeftRotation(A);
}
这段代码看上去很有美感,短小精悍。
不过我发现了一点,其实单向旋转不用使用Max比较左右节点的高度,因此我是这样实现的:
PNODE SingleRightRotation(PNODE A) // 右右旋转,返回旋转部分的根节点
{
PNODE B = A->right;
A->right = B->left;
B->left = A; A->height = Height(A->left) + ; // 这里没有通过比较更新A的高度,因为BL不会大于AL(否则在之前它们就不平衡了)
B->height = A->height + ; // 与上述理由类似 return B;
}
但是随之带来了一个问题,就是双向旋转依赖于单向旋转的实现,因此在有双向旋转操作的前提下,代码还能正确的做它应该做的事情吗?
我试着证明了一下,我的代码在无论单向还是双向旋转的情况下都是正确的:
这是我在PAT上用自己的代码AC之后与何钦铭老师的对话:
我:
我在pat上做这道题:04-树3. Root of AVL Tree (25)的时候,单向旋转是这样做的:
PNODE SingleRightRotation(PNODE A) // 右右旋转,返回旋转部分的根节点
{
PNODE B = A->right;
A->right = B->left;
B->left = A; A->height = Height(A->left) + 1; // 这里没有通过比较更新A的高度,因为BL不会大于AL(否则在之前它们就不平衡了)
B->height = A->height + 1; // 与上述理由类似 return B;
}
正如注释上所写,我认为A的高度不用通过比较来更新,我觉得其高度和BL没有关系,因为BL不可能大于AL,否则它们在之前就不平衡了,就早早的经过旋转达到平衡了。这样做以后提交正确了,因此,想跟老师确认一下,这样理解正确吗?
何钦铭老师:
你提的问题很好呀。在仅针对LL、RR旋转的情况下,你的做法是可以的(不需要max的比较)。但LR和RL也是通过两次调用SingleRightRotation和SingleLeftRotation来实现的,在这种情况下,你的做法是否仍然有效需要再仔细琢磨一下。
我:
恩恩,这个测试数据比较少,不能通过AC来证明它是正确的,但是我在理论上证明了一下,似乎可行:
首先,对于单向旋转,只需要说明一种情况正确即可,以RR旋转为例:
AL与BL的关系只有三种,即:AL = BL;AL = BL+1;AL = BL+2 综合上述三种情况,AL ≥ BL。因此无须比较。
由于节点是插在BR上的,在加上A左右两侧高度差为2这个条件,可得AL+1 = BR,但是旋转之后B为根了,所以AL+A = BR,因此更新B的高度使取AL+A或者BR两者皆可(下面会说明双向旋转的时候不可以用BR),因为它们是相等的,也无须比较。
其次,对于双向旋转,以LR旋转为例:
第一步操作是以B为根的RR旋转,而此时的B是平衡的(因为不平衡的只有A,如果不考虑A的父节点的话),要证明它的旋转也不需要比较,需要证明BL ≥ CL,而这一点由B是平衡的来保证。此外,还需要证明BL+B ≥ CR,不管插入的节点在CL还是CR,这一点同样可以由B是平衡的来保证(这里的CR相对应与单向旋转的BR,因为存在BL+B > CR的情况(与单向旋转中AL+A = BR不同),这也是单向旋转中不能用BR来更新B的高度的原因)。
接下来的操作是以A为根的LL旋转,此时C变成了A的左子树,B成了C的左子树,而且由第一步的分析可以知道各个节点的高度都得到了有效的更新,但是从层次上看, BL降了一层,CL所在的层次不变,而CR的层次上升了一层,在这种状况下要证明无须比较的LL旋转是正确的,就比较困难了,但是不难发现,只要证明不平衡的节点仍然只有A(如果节点插入到CL,那么A肯定不平衡,如果节点插入到CR,可以由BL降了一层来保证A仍然是不平衡的,其实,只要BL降了,不管节点插在CL还是CR,A就肯定不平衡了)就可以保证LL旋转的正确性,但是第一步操作有没有造成不平衡的节点产生也是需要考虑的一个方面,我的想法是不用管它,把RR旋转后的结果画出来,发现要证明LL旋转是正确的只要证明A+AR可以使得C所在的高度达到最大就可以了,这一点可以由AR不会比BL、CL、CR(CL或CR代表插入之后的高度)三个中的任何一个小来保证。 不知道这样的分析是否正确,不过,我愿意相信它,因为人类往往偏向于相信自己的直觉....
如果它是正确的话,那么在AVL树中就可以利用它提速、省空间,虽然微不足道,但是属于自己发现的,心里还是很爽的:P
All Rights Reserved.
Author:海峰:)
Copyright © xp_jiang.
转载请标明出处:http://www.cnblogs.com/xpjiang/p/4491250.html
以上.
我的新发现:AVL树旋转的一个特性的更多相关文章
- AVL树旋转
什么是AVL树? AVL树是带有平衡条件的二叉查找树,一颗AVL树首先是二叉查收树(每个节点如果有左子树或右子树,那么左子树中数据小于该节点数据,右子树数据大于该节点数据),其次,AVL树必须满足平衡 ...
- (精)AVL树旋转共8种情况(涵盖所有考研的范围)
- AVL树平衡旋转详解
AVL树平衡旋转详解 概述 AVL树又叫做平衡二叉树.前言部分我也有说到,AVL树的前提是二叉排序树(BST或叫做二叉查找树).由于在生成BST树的过程中可能会出现线型树结构,比如插入的顺序是:1, ...
- Python与数据结构[3] -> 树/Tree[2] -> AVL 平衡树和树旋转的 Python 实现
AVL 平衡树和树旋转 目录 AVL平衡二叉树 树旋转 代码实现 1 AVL平衡二叉树 AVL(Adelson-Velskii & Landis)树是一种带有平衡条件的二叉树,一棵AVL树其实 ...
- AVL树原理及实现(C语言实现以及Java语言实现)
欢迎探讨,如有错误敬请指正 如需转载,请注明出处http://www.cnblogs.com/nullzx/ 1. AVL定义 AVL树是一种改进版的搜索二叉树.对于一般的搜索二叉树而言,如果数据恰好 ...
- AVL树
AVL树 在二叉查找树(BST)中,频繁的插入操作可能会让树的性能发生退化,因此,需要加入一些平衡操作,使树的高度达到理想的O(logn),这就是AVL树出现的背景.注意,AVL树的起名来源于两个发明 ...
- PAT树_层序遍历叶节点、中序建树后序输出、AVL树的根、二叉树路径存在性判定、奇妙的完全二叉搜索树、最小堆路径、文件路由
03-树1. List Leaves (25) Given a tree, you are supposed to list all the leaves in the order of top do ...
- 数据结构与算法(九):AVL树详细讲解
数据结构与算法(一):基础简介 数据结构与算法(二):基于数组的实现ArrayList源码彻底分析 数据结构与算法(三):基于链表的实现LinkedList源码彻底分析 数据结构与算法(四):基于哈希 ...
- 红黑树与AVL树
概述:本文从排序二叉树作为引子,讲解了红黑树,最后把红黑树和AVL树做了一个比较全面的对比. 1 排序二叉树 排序二叉树是一种特殊结构的二叉树,可以非常方便地对树中所有节点进行排序和检索. 排序二叉树 ...
随机推荐
- Emmet:HTML/CSS代码快速编写神器
本文来源:http://www.iteye.com/news/27580 ,还可参考:http://www.w3cplus.com/tools/emmet-cheat-sheet.html Em ...
- jquery插件之tab标签页或滑动门
该插件乃本博客作者所写,目的在于提升作者的js能力,也给一些js菜鸟在使用插件时提供一些便利,老鸟就悠然地飞过吧. 此插件旨在实现目前较为流行的tab标签页或滑动门特效,在此插件中默认使用的是鼠标滑过 ...
- Daily Scrum 10.31
今天是万圣节,也是编译课程设计第一次作业截至的日子,但由于大家对时间的合理安排,我们还是完成了一定的任务量. 下面是今天的Task统计: 不仅燃尽图和燃速图出不来,连那个所有迭代状态的图也出不来了.. ...
- zk listbox 点击列标题实现排序功能
前台(test.zul): <?page title="测试" contentType="text/html;charset=UTF-8"?> &l ...
- 使用Fiddler截断更改Request数据
0x01 Fiddler介绍 Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,设置断点,查看所有的“进出”Fiddler的数据.(百度百科) 0x ...
- Hibernate的性能优化问题笔记
性能优化 1.注意session.clear()的运用.尤其是不断分页循环的情况下. a)在一个大集合中进行遍历,遍历取出数据或者对象 b)java会引起内存泄漏吗?在语法上是不可能出现内存泄露的,因 ...
- 使用plupload做一个类似qq邮箱附件上传的效果
公司项目中使用的框架是springmvc+hibernate+spring,目前需要做一个类似qq邮箱附件上传的功能,暂时只是上传小类型的附件 处理过程和解决方案都需要添加附件,处理过程和解决方案都可 ...
- MySQL数据恢复和复制对InnoDB锁机制的影响
MySQL通过BINLOG记录执行成功的INSERT,UPDATE,DELETE等DML语句.并由此实现数据库的恢复(point-in-time)和复制(其原理与恢复类似,通过复制和执行二进制日志使一 ...
- velocityjs 动画库 比jquery默认的animate强
神坑记录: 1.transform: translate3d(80%,0,0); 无法作为参数,必须修改为这种:translateX: 0% 官方文档 http://velocityjs.org/ g ...
- python的内存管理机制
先从较浅的层面来说,Python的内存管理机制可以从三个方面来讲 (1)垃圾回收 (2)引用计数 (3)内存池机制 一.垃圾回收: python不像C++,Java等语言一样,他们可以不用事先声明变量 ...