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树的实现的更多相关文章

  1. Java数据结构——AVL树

    AVL树(平衡二叉树)定义 AVL树本质上是一颗二叉查找树,但是它又具有以下特点:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树,并且拥有自平衡机制.在AV ...

  2. Java数据结构之树和二叉树(2)

    从这里始将要继续进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来 ...

  3. Java数据结构之树和二叉树

    从这里开始将要进行Java数据结构的相关讲解,Are you ready?Let's go~~ Java中的数据结构模型可以分为一下几部分: 1.线性结构 2.树形结构 3.图形或者网状结构 接下来的 ...

  4. 第三十二篇 玩转数据结构——AVL树(AVL Tree)

          1.. 平衡二叉树 平衡二叉树要求,对于任意一个节点,左子树和右子树的高度差不能超过1. 平衡二叉树的高度和节点数量之间的关系也是O(logn) 为二叉树标注节点高度并计算平衡因子 AVL ...

  5. 数据结构-AVL树的旋转

    http://blog.csdn.net/GabrieL1026/article/details/6311339 平衡二叉树在进行插入操作的时候可能出现不平衡的情况,AVL树即是一种自平衡的二叉树,它 ...

  6. 简单数据结构———AVL树

    C - 万恶的二叉树 Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:32768KB     64b ...

  7. java数据结构之树

    树定义和基本术语定义树(Tree)是n(n≥0)个结点的有限集T,并且当n>0时满足下列条件:     (1)有且仅有一个特定的称为根(Root)的结点:     (2)当n>1时,其余结 ...

  8. 数据结构--Avl树的创建,插入的递归版本和非递归版本,删除等操作

    AVL树本质上还是一棵二叉搜索树,它的特点是: 1.本身首先是一棵二叉搜索树.   2.带有平衡条件:每个结点的左右子树的高度之差的绝对值最多为1(空树的高度为-1).   也就是说,AVL树,本质上 ...

  9. 再回首数据结构—AVL树(一)

    前面所讲的二叉搜索树有个比较严重致命的问题就是极端情况下当数据以排序好的顺序创建搜索树此时二叉搜索树将退化为链表结构因此性能也大幅度下降,因此为了解决此问题我们下面要介绍的与二叉搜索树非常类似的结构就 ...

随机推荐

  1. appium desktop v1.2.7在android7.0上运行报错“Error: Error executing adbExec”

    1.参考下面链接,https://stackoverflow.com/questions/42283921/unable-to-run-appium-tests-on-android-7-0:得知需要 ...

  2. Java Persistence with MyBatis 3(中文版) 前言

    对很多软件系统而言,保存数据到数据库和从数据库中检索数据是其工作流程中至关重要的一部分.在 Java 领域,有很多的实现了数据持久化层的工具和框架,它们每一个都有自己不同的实现方法.而 MyBatis ...

  3. 如何让springmvc在启动的时候执行特定的业务处理

    如何让springmvc在启动的时候执行特定的业务处理 java 的 web服务器启动时,经常会做一些特定的业务逻辑处理,比如数据库初始化, 初始化系统参数,读取配置文库等. 很多web服务的中间件, ...

  4. Spring AOP 整理

    在 xml中加 xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.o ...

  5. Android canvas bug

    安卓4.1.1-4.1.2的webkit在渲染canvas元素时有bug. 具体表现是出现重影,即canvas的clearRect()方法不能彻底清空画布,仍然保留之前某个状态当“背景”. 目前的修复 ...

  6. mysql - 索引的一些理解

    推荐下这篇文章 http://blog.codinglabs.org/articles/theory-of-mysql-index.html 写的十分的不错.留着以后慢慢看,慢慢的理解.

  7. Linux查询系统信息命令

    Linux查看系统信息是比较基础的知识,所以这个应该都需要掌握,命令和解释如下: #uname -a           查看操作系统.内核.CPU信息 #head -n 1 /etc/issue   ...

  8. 编写高质量代码改善C#程序的157个建议——建议63:避免“吃掉”异常

    建议63:避免“吃掉”异常 嵌套异常是很危险的行为,一不小心就就会将异常堆栈信息,也就是真正的Bug出处隐藏起来.这还不是最严重的,最严重的就是“吃掉”异常,即捕获,然后不向上层throw. 避免“吃 ...

  9. Gym - 101498G(Super Subarray )

    In this problem, subarray is defined as non-empty sequence of consecutive elements. We define a suba ...

  10. 试题 B: 不同子串 蓝桥杯

    [问题描述]一个字符串的非空子串是指字符串中长度至少为 1 的连续的一段字符组成的串.例如,字符串aaab 有非空子串a, b, aa, ab, aaa, aab, aaab,一共 7 个.注意在计算 ...