什么是AVL树


二叉查找树的一个局限性就是有可能退化成一个链表,这种情况下二叉查找树的效率就会急剧下降变成0(n)。而AVL树可以很好地解决BST的这种困境。本篇博客会介绍AVL树的基本特点和相关操作。

文章参考自博客:二叉树-你可能需要知道的知识点


1. 什么是AVL树

任何两个子树的高度差最大是1,这样的二叉树叫做AVL树。

先来确定几个概念:

平衡因子:将二叉树上节点的左子树高度减去右子树高度的值称为该节点的平衡因子BF(Balance Factor)。

最小不平衡子树:距离插入节点最近的,且平衡因子的绝对值大于1的节点为根的子树。

左边二叉树的节点45的BF = 1,插入节点43后,节点45的BF=2。

节点45是距离插入点43最近的BF不在[-1,1]范围内的节点,因此以节点45为根的子树为最小不平衡子树。

2. 节点的实现

public class AVLTreeNode<T extends Comparable> {

    // 存储的数据-用于排序
T key; // 节点高度-用于计算父节点的BF
int height; // 左儿子 & 右儿子
AVLTreeNode<T> left;
AVLTreeNode<T> right; public AVLTreeNode() {
} public AVLTreeNode(T key, AVLTreeNode<T> left, AVLTreeNode<T> right) {
this.key = key;
this.left = left;
this.right = right;
this.height = 0;
} }

节点的定义还是比较简单的,相对于之前的定义多了一个height属性用于计算父节点的BF。

树的定义

public class AVLTree<T extends Comparable> {
// 定义树的根节点
AVLTreeNode<T> root; public AVLTree() {
root = null;
}
}

获取树的高度

    public int height() {
return height(root);
} private int height(AVLTreeNode<T> tree) {
if (tree != null){
return tree.height;
}
return 0;
}

本文章将空树的高度定义为0,高度以树的层次为准,根节点的高度为1,依次类推。

3. AVL树的调整

如果在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡。这种不平衡可能出现在下面四种情况中:

  • 对a的左儿子的左子树进行一次插入。(LL)
  • 对a的左儿子的右子树进行一次插入。(LR)
  • 对a的右儿子的左子树进行一次插入。(RL)
  • 对a的右儿子的右子树进行一次插入。(RR)

    其中1、4是关于a点的镜像对称,2、3是关于a点的镜像对称。

第一种情况(1、4)需要通过对树的一次单旋转完成调整。

第二种情况(2、3)需要通过对树的一次双旋转完成调整。

3.1 LL旋转

在左子树上插入左孩子导致AVL树失衡,"根的左子树的高度"比"根的右子树的高度"大2。针对该情况,我们需要进行单右旋转来完成对树的调整。

图中左边是旋转之前的树,右边是旋转之后的树。从中可以发现,旋转之后的树又变成了AVL树,而且该旋转只需要一次即可完成。

对于LL旋转,你可以这样理解为:LL旋转是围绕"失去平衡的AVL根节点"进行的,也就是节点4;而且由于是LL情况,就将节点4进行一次顺时针旋转。

代码实现:

    /**
* 进行一次单右旋转
*
* @param node 最小失衡树根节点
*/
private AVLTreeNode<T> rightRotation(AVLTreeNode<T> node) {
AVLTreeNode<T> left = node.left;
node.left = left.right;
left.right = node;
// 更新高度
node.height = Math.max(height(node.left), height(node.right)) + 1;
left.height = Math.max(height(left.left), height(left.right)) + 1;
return left;
}

3.2 RR旋转

在右子树插入右孩子导致AVL失衡时,我们需要进行单左旋调整。旋转围绕最小失衡子树的根节点进行。

    /**
* 进行一次单左旋转
*
* @param node 最小失衡树根节点
*/
private AVLTreeNode<T> leftRotation(AVLTreeNode<T> node) {
AVLTreeNode<T> right = node.right;
node.right = right.left;
right.left = node; // 更新高度
node.height = Math.max(height(node.left), height(node.right)) + 1;
right.height = Math.max(height(right.left), height(right.right)) + 1; return right; }

3.3 RL旋转

“在右子树上插入左孩子导致AVL树失衡",此时我们需要进行先右旋后左旋的调整。


/**
* 先右旋后左旋
*
* @param node 失衡树根节点
* @return 旋转后的根节点
*/
private AVLTreeNode<T> rightLeftRotation(AVLTreeNode<T> node) {
node.right = rightRoation(node.right); return leftRoation(node); }

3.4 LR旋转

“在左子树上插入右孩子导致AVL树失衡",此时我们需要进行先左旋后右旋的调整。


/**
* 先左旋后右旋
*
* @param node 失衡树根节点
* @return 旋转后的根节点
*/
private AVLTreeNode<T> leftRightRotation(AVLTreeNode<T> node) {
node.left = leftRoation(node.left); return rightLeftRoation(node); }

【数据结构】什么是AVL树的更多相关文章

  1. 数据结构与算法——AVL树类的C++实现

    关于AVL树的简单介绍能够參考:数据结构与算法--AVL树简单介绍 关于二叉搜索树(也称为二叉查找树)能够參考:数据结构与算法--二叉查找树类的C++实现 AVL-tree是一个"加上了额外 ...

  2. 【数据结构】平衡二叉树—AVL树

    (百度百科)在计算机科学中,AVL树是最先发明的自平衡二叉查找树.在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树.查找.插入和删除在平均和最坏情况下都是O(log n).增 ...

  3. 数据结构(三)实现AVL树

    AVL树的定义 一种自平衡二叉查找树,中面向内存的数据结构. 二叉搜索树T为AVL树的满足条件为: T是空树 T若不是空树,则TL.TR都是AVL树,且|HL-HR| <= 1 (节点的左子树高 ...

  4. 数据结构与算法分析-AVL树

    1.AVL树是带有平衡条件的二叉查找树. 2.AVL树的每个节点高度最多相差1. 3.AVL树实现的难点在于插入或删除操作.由于插入和删除都有可能破坏AVL树高度最多相差1的特性,所以当特性被破坏时需 ...

  5. 数据结构——二叉查找树、AVL树

    二叉查找树:由于二叉查找树建树的过程即为插入的过程,所以其中序遍历一定为升序排列! 插入:直接插入,插入后一定为根节点 查找:直接查找 删除:叶子节点直接删除,有一个孩子的节点删除后将孩子节点接入到父 ...

  6. [数据结构与算法] : AVL树

    头文件 typedef int ElementType; #ifndef _AVLTREE_H_ #define _AVLTREE_H_ struct AvlNode; typedef struct ...

  7. AVL树和伸展树 -数据结构(C语言实现)

    读数据结构与算法分析 AVL树 带有平衡条件的二叉树,通常要求每颗树的左右子树深度差<=1 可以将破坏平衡的插入操作分为四种,最后通过旋转恢复平衡 破坏平衡的插入方式 描述 恢复平衡旋转方式 L ...

  8. 数据结构图文解析之:AVL树详解及C++模板实现

    0. 数据结构图文解析系列 数据结构系列文章 数据结构图文解析之:数组.单链表.双链表介绍及C++模板实现 数据结构图文解析之:栈的简介及C++模板实现 数据结构图文解析之:队列详解与C++模板实现 ...

  9. 图解数据结构树之AVL树

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

  10. 深入浅出数据结构C语言版(12)——平衡二叉查找树之AVL树

    在上一篇博文中我们提到了,如果对普通二叉查找树进行随机的插入.删除,很可能导致树的严重不平衡 所以这一次,我们就来介绍一种最老的.可以实现左右子树"平衡效果"的树(或者说算法),即 ...

随机推荐

  1. Keras实例教程(2)

    https://blog.csdn.net/baimafujinji/article/details/78385745

  2. 单元测试之NUnit三

    NUnit 分三篇文章介绍,入门者可阅读文章,有基础者直接参考官方文档.初次写博客,望大家指点. 导航: 单元测试之NUnit一 单元测试之NUnit二 单元测试之NUnit三 除了Assert断言外 ...

  3. Django基础知识点

    HTTP协议:  请求方式: 有8种分别是GET POST DELTE PUT OPTIONS HEAD 状态码: 2xx   200 OK 3xx   重定向 4xx   请求的错误 5xx   服 ...

  4. hibernate 报错com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException

    解释:JavaBean的主键类型只能是int类型,因为在映射关系配置是自动增长的,String类型是不能自动增长的,所以会报错.

  5. 设计模式(C#)——11代理模式

    推荐阅读:  我的CSDN  我的博客园  QQ群:704621321 前言        在软件开发过程中,当无法直接访问某个对象或访问某个对象存在困难时,我们希望可以通过一个中介来间接访问,这就是 ...

  6. Fire Balls 05——子弹的命中及后续效果

    版权申明: 本文原创首发于以下网站: 博客园『优梦创客』的空间:https://www.cnblogs.com/raymondking123 优梦创客的官方博客:https://91make.top ...

  7. 用jquery uploadify上传插件上传文件

    public void ProcessRequest(HttpContext context) { string esOIDs = System.Web.HttpContext.Current.Req ...

  8. Super和This总结

    this: this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针. Java关键字this只能用于方法体内.当一个对象创建后,Java虚拟机(JVM)就会给这个对象分配一个引用自 ...

  9. Java-手动搭建SSM(Maven)

    一.环境部署 操作系统:windows10专业版 jdk:1.8.0_144 IDE:eclipse-oxygen 服务器:tomcat 9.0 数据库:mysql 5.7.18 Maven:3.54 ...

  10. 依赖倒置原则(DIP)、控制反转(IoC)、依赖注入(DI)(C#)

    理解: 依赖倒置原则(DIP)主程序要依赖于抽象接口,不要依赖于具体实现.高层模块不应该依赖底层模块,两个都应该以来抽象.抽象不应该依赖细节,细节应该依赖抽象.(具体看我上一篇贴子) 依赖倒置原则是六 ...