AVL树(二叉平衡树)详解与实现
AVL树概念
前面学习二叉查找树和二叉树的各种遍历,但是其查找效率不稳定(斜树),而二叉平衡树的用途更多。查找相比稳定很多。(欢迎关注数据结构专栏)
- AVL树是带有平衡条件的二叉查找树。这个平衡条件必须要
容易保持。而且要保证它的深度是O(logN). - AVL的条件是左右树的高度差(
平衡因子)不大于1;并且它的每个子树也都是平衡二叉树。 - 对于平衡二叉树的最小个数,
n0=0;n1=1;nk=n(k-1)+n(k-2)+1;(求法可以类比斐波那契!)
难点:AVL是一颗二叉排序树,用什么样的规则或者规律让它能够在复杂度不太高的情况下实现动态平衡呢?

不平衡概况

如果简单的以单节点看,大致有上面四种情形,并且他们的最后结果也是有的有所相近。只是:上下会变动。该在左面的还在左面,改在右面的还在右面。

这只是针对在底部,对于可能出现的平衡要首先搞清楚:

所以针对四种不平衡,可能出现在底部,也可能出现在头,也可能出现在某个中间节点导致不平衡。 而我们只需要研究其首次不平衡点,解决之后整棵树即继续平衡。当然,在实际解决肯定会带上递归的思想解决问题。
四种平衡旋转方式
RR平衡旋转(左单旋转)

出现这种情况的原因是节点的右侧的右侧较深这时候不平衡节点需要左旋。再细看过程。
- 再左旋的过程中,
root(oldroot)节点下沉,中间节点(newroot)上浮.而其中中间节点(newroot)的右侧依然不变。 - 它上浮左侧所以需要指向
根节点(oldroot)(毕竟一棵树)。但是这样newroot原来左侧节点H空缺。而我们需要仍然让整个树完整并且满足二叉排序树的规则。 - 而刚好本来oldroot右侧指向newroot变成oldroot被newroot左侧指向。所以
oldroot右侧空缺,刚好这个位置满足在oldroot的右侧。在newroot的左侧。.所以我们将H插入在这个位置。 - 其中H可能为
NULL。不过不影响操作!

而左旋的代码可以表示为:
private node getRRbanlance(node oldroot) {//右右深,需要左旋
// TODO Auto-generated method stub
node newroot=oldroot.right;
oldroot.right=newroot.left;
newroot.left=oldroot;
oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1;
newroot.height=Math.max(getHeight(newroot.left),getHeight(newroot.right))+1;//原来的root的高度需要从新计算
return newroot;
}
LL平衡旋转(右单旋转)
而右旋和左旋相反,但是思路相同,根据上述进行替换即可!

代码:
private node getLLbanlance(node oldroot) {//LL小,需要右旋转
// TODO Auto-generated method stub
node newroot=oldroot.left;
oldroot.left=newroot.right;
newroot.right=oldroot;
oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1;
newroot.height=Math.max(getHeight(newroot.left),getHeight(newroot.right))+1;//原来的root的高度需要从新金酸
return newroot;
}
RL平衡旋转(先右后左双旋转)
产生不平衡的条件原因是:
root节点右侧左侧节点的深度高些,使得与左侧的差大于1.这个与我们前面看到的左旋右旋不同的是因为它的结构不能直接变一下就可以完成。- 因为对于右左结构,中间的最大,两侧的最小。但是下面的比上面大(
下面在上面右侧)所以如果平衡的话,那么右左的R.L应该在中间,而R应该在右侧。原来的root在左侧。 - 所以节点的变化浮动比较大,而且需要妥善处理各个子节点的移动使其满足二叉排序树的性质!
- 期间考虑树高度变化即可!
这种双旋转其实也很简单。不要被外表唬住。基于前面的单旋转,双旋转有两种具体逻辑思路。
思路1:两次旋转RR,LL

根据上图所圈的,先对底部使得底部的大小关系变化,使其在满足二叉平衡树的条件下还满足RR结构的二叉树。所以只需要对右节点R先进行右旋,再对ROOT进行左旋即可。
思路2:直接分析
根据初始和结果的状态,然后分析各个节点变化顺序。手动操作这些节点即可!
- 首先根据
ROOT,R,R.L三个节点变化。R.L肯定要在最顶层。左右分别指向ROOT和R。那么这其中R.left,ROOT.right发生变化(原来分别是R,L和R)暂时为空。而刚好根据左右大小关系可以补上R.L的左右节点。 - 这样思考整棵树也可以完成平衡,但是要考虑树的高度变化。

代码为:(注释部分为方案1)
private node getRLbanlance(node oldroot) {//右左深
// node newroot=oldroot.right.left;
// oldroot.right.left=newroot.right;
// newroot.right=oldroot.right;
// oldroot.right=newroot.left;
// newroot.left=oldroot;
// oldroot.height=Math.max(getHeight(oldroot.left),getHeight(oldroot.right))+1;
// newroot.right.height=Math.max(getHeight(newroot.right.left),getHeight(newroot.right.right))+1;
// newroot.height=Math.max(getHeight(oldroot.left),getHeight(newroot.right))+1;//原来的root的高度需要从新金酸
oldroot.right =getLLbanlance(oldroot.right);
oldroot.height=Math.max(getHeight(oldroot.left), getHeight(oldroot.right))+1;
return getRRbanlance(oldroot);
}
LR平衡旋转(先左后右单旋转)
根据上述RL修改即可

private node getLRbanlance(node oldroot) {
oldroot.left =getRRbanlance(oldroot.left);
oldroot.height=Math.max(getHeight(oldroot.left), getHeight(oldroot.right))+1;
return getLLbanlance(oldroot);
}
java代码实现
- 首先对于节点多个
height属性。用于计算高度(平衡因子) - 插入是递归插入。递归一个来回的过程,去的过程进行插入。回的过程进行高度更新。和检查是否平衡。不要写全局递归计算高度,效率太低下。事实上高度变化只和插入和平衡有关,仔细考虑即不会有疏漏!



总结
测试情况:

- AVL的理解需要时间,当然笔者的AVL自己写的
可能有些疏漏,如果有问题还请各位一起探讨! - 当然,除了插入,AVL还有
删除等其他操作,(原理相似。删除后平衡)有兴趣可以一起研究。 - 如果需要源码还请关注笔者公众号:公众号查看相关专题文章!
- 如果对
后端、爬虫、数据结构算法等感性趣欢迎关注我的个人公众号交流:bigsai(回复数据结构、爬虫、java等有精心准备资料一份!)

AVL树(二叉平衡树)详解与实现的更多相关文章
- 数据结构图文解析之:二叉堆详解及C++模板实现
0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...
- 二叉搜索树详解(Java实现)
1.二叉搜索树定义 二叉搜索树,是指一棵空树或者具有下列性质的二叉树: 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值: 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根 ...
- 树-二叉平衡树AVL
基本概念 AVL树:树中任何节点的两个子树的高度最大差别为1. AVL树的查找.插入和删除在平均和最坏情况下都是O(logn). AVL实现 AVL树的节点包括的几个组成对象: (01) key -- ...
- 哈夫曼树(二)之 C++详解
上一章介绍了哈夫曼树的基本概念,并通过C语言实现了哈夫曼树.本章是哈夫曼树的C++实现. 目录 1. 哈夫曼树的介绍 2. 哈夫曼树的图文解析 3. 哈夫曼树的基本操作 4. 哈夫曼树的完整源码 转载 ...
- AVL树的旋转操作详解
[0]README 0.0) 本文部分idea 转自:http://blog.csdn.net/collonn/article/details/20128205 0.1) 本文仅针对性地分析AVL树的 ...
- java项目---用java实现二叉平衡树(AVL树)并打印结果(详)(3星)
package Demo; public class AVLtree { private Node root; //首先定义根节点 private static class Node{ //定义Nod ...
- 从零开始学算法---二叉平衡树(AVL树)
先来了解一些基本概念: 1)什么是二叉平衡树? 之前我们了解过二叉查找树,我们说通常来讲, 对于一棵有n个节点的二叉查找树,查询一个节点的时间复杂度为log以2为底的N的对数. 通常来讲是这样的, 但 ...
- 二叉搜索树、AVL平衡二叉搜索树、红黑树、多路查找树
1.二叉搜索树 1.1定义 是一棵二叉树,每个节点一定大于等于其左子树中每一个节点,小于等于其右子树每一个节点 1.2插入节点 从根节点开始向下找到合适的位置插入成为叶子结点即可:在向下遍历时,如果要 ...
- Algorithms: 二叉平衡树(AVL)
二叉平衡树(AVL): 这个数据结构我在三月份学数据结构结构的时候遇到过.但当时没调通.也就没写下来.前几天要用的时候给调好了!详细AVL是什么,我就不介绍了,维基百科都有. 后面两月又要忙了. ...
随机推荐
- 洛谷P4994 终于结束的起点 题解
求赞,求回复,求关注~ 题目:https://www.luogu.org/problemnew/show/P4994 这道题和斐波那契数列的本质没有什么区别... 分析: 这道题应该就是一个斐波那契数 ...
- 个人永久性免费-Excel催化剂功能第60波-数据有效性验证增强版,补足Excel天生不足
Excel在数据处理.数据分析上已经是公认的最好用的软件之一,其易用性和强大性也吸引无数的初中高级用户每天都在使用Excel.但这些优点的同时,也带出了一些问题,正因为其不同于一般的专业软件,需要专业 ...
- Excel催化剂开源第29波-在Winform上使用富文本编辑器控件
富文本编辑器,一般都是BS架构专利一般,好像百度有一个开源的比较出名,但无奈这些都只能用在JS上,在BS网页端开发上使用.像Winform开发的VSTO,只能羡慕的份.和一般Winform上用的Ric ...
- [leetcode]python 283. Move Zeroes
Given an array nums, write a function to move all 0's to the end of it while maintaining the relativ ...
- 关于 64位系统 java连接access 报错java.sql.SQLException: [Microsoft][ODBC 驱动程序管理器] 未发现数据源名称并且未指定默认驱动程序
报错的原因是url = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=E:/公司/2000.mdb"; 这样是不行 ...
- MacBook Air多出一块磁盘?
今天将MAC的系统升级到Mojave,启动之后发现系统挂载的磁盘变了,我记得升级之前文件系统是挂载在/dev/disk0上的,但是升级之后,文件系统挂载在/dev/disk1上了. 用diskutil ...
- 在工作中常用到的SQL
前言 只有光头才能变强. 文本已收录至我的GitHub仓库,欢迎Star:https://github.com/ZhongFuCheng3y/3y 最近在公司做了几张报表,还记得刚开始要做报表的时候都 ...
- Redis 学习笔记(篇七):Redis 持久化
因为 Redis 是内存数据库,它将自己的数据储存在内存里面,所以如果不想办法将储存在内存中的数据库状态保存到磁盘里面,那么一旦服务器进程退出,服务器中的数据也将会丢失,为了解决这个问题,Redis ...
- CodeForces 372 A. Counting Kangaroos is Fun
题意,有n只袋鼠,没每只袋鼠有个袋子,大小为si,一个袋鼠可以进入另外一个袋鼠的袋子里面,当且仅当另一个袋鼠的袋子是他的二倍或二倍一上,然后中国袋鼠就是不可见的,不能出现多个袋鼠嵌套的情况.让你求最少 ...
- ES2019 / ES10有什么新功能?
ECMAScript(简称ES)是ECMA International在ECMA-262和ISO / IEC 16262中标准化的脚本语言规范.它是为了标准化JavaScript语言而创建的,以便从浏 ...