什么是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. Ubuntu Server : 自动更新

    Ubuntu(16.04/18.04) 默认会每天自动安装系统的安全更新,但是不会自动安装包的更新.本文梳理 Ubuntu 16.04/18.04 系统的自动更新机制,并介绍如何配置系统自动更新所有的 ...

  2. Python day02 课堂笔记

    今天是第二天学习Python课程,主要从格式化输出,逻辑运算,编码,数据类型 这几个方面来学习. 1.格式化输出: % : 占位符 %s:字符串 %d:数字 注意: 在格式化的输出中,如果要输出%(因 ...

  3. Redis缓存,持久化,高可用

    一,Redis作缓存服务器 ​ 本篇博客是接着上一篇博客未分享完的技术点. ​ redis作为缓存服务器是众多企业中的选择之一,虽然该技术很成熟但也是存在一定的问题.就是缓存带来的缓存穿透,缓存击穿, ...

  4. helm安装kafka集群并测试其高可用性

    介绍 Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写.Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据. 这种动作( ...

  5. 回顾js中的cookie/localstorage

    1.首先简单总结下cookie cookie:可以做会话跟踪 特点:      1.大小限制(不能超过4k)      2.每个域下cookie不能超过50个      3.有效期(和设定时间有关), ...

  6. c++采集windows操作系统名称

    WINAPI windows通过c++获取操作系统主要分两种: 1. windows是8.1版本以下版本:获取操作系统可以通过windows提供的api中GetVersionEx函数来获取 2. wi ...

  7. HillCrest Sensor HAL

    1. 抽象定义 Google为Sensor提供了统一的HAL接口,不同的硬件厂商需要根据该接口来实现并完成具体的硬件抽象层,Android中Sensor的HAL接口定义在:hardware/libha ...

  8. emlog博客的安装教程

    简介 emlog 是一款基于PHP和MySQL的功能强大的博客及CMS建站系统.致力于为您提供快速.稳定,且在使用上又极其简单.舒适的内容创作及站点搭建服务. 安装步骤 1.将src文件夹下的所有文件 ...

  9. 8、kubernetes之存储卷资源

    一.存储卷的类型 emptyDir:在宿主机上分一块内存空间给pod当做存储空间 hostPath:在宿主机上分一块磁盘空间给pod当做存储空间 网络存储: SAN:iSCSI,FC NAS:nfs, ...

  10. Oracle数据库测试和优化最佳实践: OTest介绍 (转)

    当前Oracle数据库最佳测试工具OTest *  Otest是用于Oracle数据库测试.优化.监控软件. *  Otest是免费提供给Oracle客户和广大DBA工程师使用的软件.由原厂技术专家王 ...