JAVA数据结构--AVL树的实现
AVL树的定义
在计算机科学中,AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下的时间复杂度都是
。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者G. M. Adelson-Velsky和E. M. Landis,他们在1962年的论文《An algorithm for the organization of information》中发表了它。
节点的平衡因子是它的左子树的高度减去它的右子树的高度(有时相反)。带有平衡因子1、0或 -1的节点被认为是平衡的。带有平衡因子 -2或2的节点被认为是不平衡的,并需要重新平衡这个树。平衡因子可以直接存储在每个节点中,或从可能存储在节点中的子树高度计算出来。

上图是摘自维基百科的AVL树实现的图例,比较清晰的解释了AVL调整平衡的过程。ABCD代表当前节点有子树。
我以我个人理解以左右情况为例
该例是左右情况,需要将其调整为左左或者右右才能继续调整。因为节点5是在右,所以3节点(虚线方框内)调整为左为最佳。左旋转即可使树变为左左形状。
AVL树节点定义
private static class AvlNode<T>{
public AvlNode(T theElement) {
this(theElement, null, null);
}
public AvlNode(T theElement,AvlNode<T> lt,AvlNode<T> rt) {
element=theElement;
left=lt;
right=rt;
height=0;
}
T element;
AvlNode<T> left;
AvlNode<T> right;
int height;
}
与二叉查找树的定义类似,不过加入了节点的深度height定义。
AVL节点计算方法
private int height(AvlNode<T> t) {
return t==null?-1:t.height;
}
当banlance()或者旋转时height都会改变
节点旋转
/*
* 实现单旋转
* */
private AvlNode<T> rotateWithLeftChild(AvlNode<T> k2){//单左旋转
AvlNode<T> k1=k2.left;
k2.left=k1.right;
k1.right=k2;
k2.height=Math.max(height(k2.left), height(k2.right))+1;
k1.height=Math.max(height(k1.left), k2.height)+1;
return k1;
}
private AvlNode<T> rotateWithRightChild(AvlNode<T> k1){//单右旋转
AvlNode<T> k2=k1.right;
k1.right=k2.left;
k2.left=k1;
k2.height=Math.max(height(k1.left), height(k1.right))+1;
k1.height=Math.max(height(k2.right), k1.height)+1;
return k2;
}
/*
* 实现双旋转
*
* */
private AvlNode<T> doubleWithLeftChild(AvlNode<T> k3){//先右旋转再左旋转
k3.left=rotateWithRightChild(k3.left);
return rotateWithLeftChild(k3);
}
private AvlNode<T> doubleWithRightChild( AvlNode<T> k1 ){//先左旋转再右旋转
k1.right = rotateWithLeftChild( k1.right );
return rotateWithRightChild( k1 );
}
balance()方法的实现
private AvlNode<T> balance(AvlNode<T> t){
if(t==null)
return t;
if(height(t.left)-height(t.right)>ALLOWED_IMBALANCE) {//左子树高度过高
if(height(t.left.left)>=height(t.left.right))//判断进行单旋转还是双旋转
t=rotateWithLeftChild(t);
else
t=doubleWithLeftChild(t);
}
else if (height(t.right)-height(t.left)>ALLOWED_IMBALANCE) {//右子树高度过高
if(height(t.right.right)>=height(t.right.left))
t=rotateWithRightChild(t);
else
t=doubleWithRightChild(t);
}
t.height=Math.max(height(t.left), height(t.right))+1;
return t;
}
删除节点方法
private AvlNode<T> remove(T x,AvlNode<T> t){
if(t==null)
return t;
int compareResult=x.compareTo(t.element);
if(compareResult<0)
t.left=remove(x, t.left);//递归查找删除
else if (compareResult>0) {
t.right=remove(x, t.right);
}
else if (t.left!=null&&t.right!=null) {//要删除的节点两个孩子节点的情况
t.element=findMin(t.right).element;//从右子树中找出最小的节点替换当前要删除的节点
t.right=remove(t.element, t.right);//删除右子树中需要拿出替换的节点
}
else {
t=(t.left!=null)?t.left:t.right;//单个子节点的情况
}
return balance(t);
}
完整代码如下(不含遍历),github地址
package Tree;
public class AvlTree <T extends Comparable<? super T>>{
private static class AvlNode<T>{
public AvlNode(T theElement) {
this(theElement, null, null);
}
public AvlNode(T theElement,AvlNode<T> lt,AvlNode<T> rt) {
element=theElement;
left=lt;
right=rt;
height=0;
}
T element;
AvlNode<T> left;
AvlNode<T> right;
int height;
}
private AvlNode<T> root;//定义根节点
public AvlTree() {
root=null;
}
public int height() {
return height(root);
}
public void insert(T x) {
insert(x, root);
}
public void remove(T x) {
root=remove(x,root);
}
private int height(AvlNode<T> t) {
return t==null?-1:t.height;
}
private AvlNode<T> insert(T x,AvlNode<T> t){
if(t==null)
return new AvlNode<T>(x, null, null);
int compareResult=x.compareTo(t.element);
if(compareResult<0) {
t.left=insert(x, t.left);
}
else if(compareResult>0){
t.right=insert(x, t.right);
}
else { }
return balance(t); }
private AvlNode<T> balance(AvlNode<T> t){
if(t==null)
return t;
if(height(t.left)-height(t.right)>ALLOWED_IMBALANCE) {//左子树高度过高
if(height(t.left.left)>=height(t.left.right))//判断进行单旋转还是双旋转
t=rotateWithLeftChild(t);
else
t=doubleWithLeftChild(t);
}
else if (height(t.right)-height(t.left)>ALLOWED_IMBALANCE) {//右子树高度过高
if(height(t.right.right)>=height(t.right.left)) t=rotateWithRightChild(t);
else
t=doubleWithRightChild(t);
}
t.height=Math.max(height(t.left), height(t.right))+1;
return t;
}
/*
* 实现单旋转
* */
private AvlNode<T> rotateWithLeftChild(AvlNode<T> k2){//单左旋转
AvlNode<T> k1=k2.left;
k2.left=k1.right;
k1.right=k2;
k2.height=Math.max(height(k2.left), height(k2.right))+1;
k1.height=Math.max(height(k1.left), k2.height)+1;
return k1;
}
private AvlNode<T> rotateWithRightChild(AvlNode<T> k1){//单右旋转
AvlNode<T> k2=k1.right;
k1.right=k2.left;
k2.left=k1;
k2.height=Math.max(height(k1.left), height(k1.right))+1;
k1.height=Math.max(height(k2.right), k1.height)+1;
return k2;
}
/*
* 实现双旋转
*
* */
private AvlNode<T> doubleWithLeftChild(AvlNode<T> k3){//先右旋转再左旋转
k3.left=rotateWithRightChild(k3.left);
return rotateWithLeftChild(k3);
}
private AvlNode<T> doubleWithRightChild( AvlNode<T> k1 ){//先左旋转再右旋转
k1.right = rotateWithLeftChild( k1.right );
return rotateWithRightChild( k1 );
}
private AvlNode<T> remove(T x,AvlNode<T> t){
if(t==null)
return t;
int compareResult=x.compareTo(t.element);
if(compareResult<0)
t.left=remove(x, t.left);//递归查找删除
else if (compareResult>0) {
t.right=remove(x, t.right);
}
else if (t.left!=null&&t.right!=null) {//要删除的节点两个孩子节点的情况
t.element=findMin(t.right).element;//从右子树中找出最小的节点替换当前要删除的节点
t.right=remove(t.element, t.right);//删除右子树中需要拿出替换的节点
}
else {
t=(t.left!=null)?t.left:t.right;//单个子节点的情况
}
return balance(t);
}
private AvlNode<T> findMin(AvlNode<T> t){
//非递归写法
if(t!=null)
while(t.left!=null)
t=t.left;
return t;
//递归写法
/*if(t==null)
return null;
else if (t.left==null) {
return t;
}
return findMin(t.left);*/
}
private static final int ALLOWED_IMBALANCE=1; }
JAVA数据结构--AVL树的实现的更多相关文章
- Java数据结构——AVL树
AVL树(平衡二叉树)定义 AVL树本质上是一颗二叉查找树,但是它又具有以下特点:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树,并且拥有自平衡机制.在AV ...
- Java数据结构之树和二叉树(2)
从这里始将要继续进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来 ...
- Java数据结构之树和二叉树
从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...
- 第三十二篇 玩转数据结构——AVL树(AVL Tree)
1.. 平衡二叉树 平衡二叉树要求,对于任意一个节点,左子树和右子树的高度差不能超过1. 平衡二叉树的高度和节点数量之间的关系也是O(logn) 为二叉树标注节点高度并计算平衡因子 AVL ...
- 数据结构-AVL树的旋转
http://blog.csdn.net/GabrieL1026/article/details/6311339 平衡二叉树在进行插入操作的时候可能出现不平衡的情况,AVL树即是一种自平衡的二叉树,它 ...
- 简单数据结构———AVL树
C - 万恶的二叉树 Crawling in process... Crawling failed Time Limit:1000MS Memory Limit:32768KB 64b ...
- java数据结构之树
树定义和基本术语定义树(Tree)是n(n≥0)个结点的有限集T,并且当n>0时满足下列条件: (1)有且仅有一个特定的称为根(Root)的结点: (2)当n>1时,其余结 ...
- 数据结构--Avl树的创建,插入的递归版本和非递归版本,删除等操作
AVL树本质上还是一棵二叉搜索树,它的特点是: 1.本身首先是一棵二叉搜索树. 2.带有平衡条件:每个结点的左右子树的高度之差的绝对值最多为1(空树的高度为-1). 也就是说,AVL树,本质上 ...
- 再回首数据结构—AVL树(一)
前面所讲的二叉搜索树有个比较严重致命的问题就是极端情况下当数据以排序好的顺序创建搜索树此时二叉搜索树将退化为链表结构因此性能也大幅度下降,因此为了解决此问题我们下面要介绍的与二叉搜索树非常类似的结构就 ...
随机推荐
- code1225 搭积木
题目分析:将当前层定义为第h层,共用了n块积木,本层积木数为m,f(h,n,m) 那么可以扩展数两种状态:f(h-1,n-m,m-1),f(h-1,n-m,m+1) 直接搜索可能的数据达到h^m,超时 ...
- Python的内建比较函数cmp比较原理剖析-乾颐堂
cmp( x, y):比较2个对象,前者小于后者返回-1,相等则返回0,大于后者返回1. Python的cmp比较函数比较原理 Python的cmp函数可以比较同类型之间,或者不同数据类型之间.然后根 ...
- easyui combogrid 下拉框 智能输入
1. 后台代码 using System;using System.Collections;using System.Collections.Generic;using System.Linq;usi ...
- 关于设置了setMaxAge(0)而浏览器未成功删除Cookie的注意事项
最近做了个系统,其中涉及到对Cookie的操作.当用户登录时,设置一些数据到Cookie中,用户登出系统的时候删除写入浏览器中的对应Cookie.问题就出在登出系统时,在firebug中看到需要删除的 ...
- 37 有n个人围成一圈,顺序排号,从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号那位.
题目:有n个人围成一圈,顺序排号,从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号那位. public class _037NumberOff { public st ...
- HDU 5119 Happy Matt Friends(DP || 高斯消元)
题目链接 题意 : 给你n个数,让你从中挑K个数(K<=n)使得这k个数异或的和小于m,问你有多少种异或方式满足这个条件. 思路 : 正解据说是高斯消元.这里用DP做的,类似于背包,枚举的是异或 ...
- Arch Linux freemind中文乱码
原因:jre没有可用的中文字体 解决方法: (1) 安装中文字体,例如文泉驿微黑 pacman -S wqy-microhei (2) jre字体目录下建立fallback,并链接中文字体作为后备字体 ...
- 深入理解java虚拟机(十三) Java 即时编译器JIT机制以及编译优化
在部分的商用虚拟机中,Java 程序最初是通过解释器( Interpreter )进行解释执行的,当虚拟机发现某个方法或代码块的运行特别频繁的时候,就会把这些代码认定为“热点代码”.为了提高热点代码的 ...
- 配置hive环境以及mysql配置后必须做
1.先在主节点上安装阿里云配置(看别的文档) 2.把需要的两个jar包加入进来(放到hadoop用户目录下面即可即/home/hadoop/) mysql-connector-java-5.1.47. ...
- Linq扩展最后遗留之SelectMany,Zip,SequenceEqual源码分析
Linq扩展最后遗留之SelectMany,Zip,SequenceEqual源码分析 一: AsParallel [并行化查询] 这个函数的功效就是将计算结果多线程化.[并行计算] =>[多核 ...
该例是左右情况,需要将其调整为左左或者右右才能继续调整。因为节点5是在右,所以3节点(虚线方框内)调整为左为最佳。左旋转即可使树变为左左形状。