图解AVL树
1:AVL树简介
二叉搜索树在一般情况下其搜索的时间复杂度为O(logn),但某些特殊情况下会退化为链表,导致树的高度变大且搜索的时间复杂度变为O(n),发挥不出树这种数据结构的优势,因此平衡二叉树便应运而生,通过保证树的高度来保证查询的时间复杂度为O(logn),想想人类实在是太聪明了!
2:构造AVL树
在构造一棵AVL树的时候如何保持平衡呢?其手段便是通过各种旋转变换来调整以此保证整棵树的高度,调整的原则是左右子树的高度不能大于1的绝对值(平衡因子)先来介绍下旋转的方法吧。
2.1:LL型
当插入元素后构成LL型,如下图所示,则以2为支,高右转,把3右旋下来保证平衡。
2.2:RR型
当插入元素后构成RR型,如下图所示,则以2为支,高左转,把1左旋转下来保证平衡。
2.3:LR型
当插入元素后构成LR型,如下图所示,先2,3整体左旋,在根据LL型进行右旋转来保证平衡。
2.4:RL型
当插入元素后构成RL型,如下图所示,先将5右转,在与6进行交换,在根据RR型进行旋转来保证平衡。
2.5:其他情况
当因为插入一个元素而导致出现两个不平衡点,应该调整距离插入节点最近的不平衡点
2.6:自测题
测试题:以关键字序列{16、3、7、11、9、26、18、14、15}构造一颗AVL树
2.7:java实现AVL的构造
package AVL;
/**
* @author admin
* @version 1.0.0
* @ClassName AVLTree.java
* @Description TODO
* @createTime 2020年03月30日 18:28:00
*/
public class AVLTree {
/**
* 获取左右节点的高度差,即平衡因子
* @param root
* @return
*/
public int getBalance(Node root) {
return root==null?0:getHeight(root.left)-getHeight(root.right);
}
/**
* 获取节点的高度
* @param root
* @return
*/
public int getHeight(Node root) {
return root == null ? 0 : root.height;
}
/**
* 更新节点的高度
* @param root
* @return
*/
private int updateHeight(Node root) {
if (root == null)
return 0;
return Math.max(updateHeight(root.left), updateHeight(root.right)) + 1;
}
/**
* LL型,右旋操作
*
* @param root
* @return
*/
public Node rightRotate(Node root) {
Node node = root.left;
root.left = node.right;
node.right = root;
root.height = updateHeight(root);
node.height = updateHeight(node);
return node;
}
/**
* RR型,左旋操作
* @param root
* @return
*/
public Node leftRotate(Node root) {
Node node = root.right;
root.right = node.left;
node.left = root;
root.height = updateHeight(root);
node.height = updateHeight(node);
return node;
}
public Node insert(Node node, int data) {
//当节点为空,直接插入
if (node == null) {
return (new Node(data));
}
//当插入元素<node.data,往node的左子树进行插入;>node.data,往node的右子树插入
if (node.data > data) {
node.left = insert(node.left, data);
} else {
node.right = insert(node.right, data);
}
//更新节点的高度
node.height = updateHeight(node);
//获取平衡因子(左子树高度-右子树高度)
int balDiff = getBalance(node);
// 右旋
if (balDiff > 1 && data < node.left.data) {
return rightRotate(node);
}
// 左旋
if (balDiff < -1 && data > node.right.data) {
return leftRotate(node);
}
// 先左旋在右旋
if (balDiff > 1 && data > node.left.data) {
node.left = leftRotate(node.left);
return rightRotate(node);
}
// 先右旋在左旋
if (balDiff < -1 && data < node.right.data) {
node.right = rightRotate(node.right);
return leftRotate(node);
}
return node;
}
}
class Node {
int data;
Node left;
Node right;
int height;
public Node(Integer data) {
this.data = data;
height = 1;
}
}
3:AVL树的删除
3.1:删除叶子节点
3.2:删除只拥有左子树或右子树的节点
3.3:删除既拥有左子树又有右子树的节点
3.4:自测题
将上一道自测题的图依次删除16,15,11节点,画出最后的结果
参考链接
数据可视化网站: https://visualgo.net/zh
哔哩哔哩讲AVL:https://www.bilibili.com/video/BV1xE411h7dd
图解AVL树的更多相关文章
- AVL树的插入操作(旋转)图解
=================================================================== AVL树的概念 在说AVL树的概念之前,我们需要清楚 ...
- 平衡二叉树,AVL树之图解篇
学习过了二叉查找树,想必大家有遇到一个问题.例如,将一个数组{1,2,3,4}依次插入树的时候,形成了图1的情况.有建立树与没建立树对于数据的增删查改已经没有了任何帮助,反而增添了维护的成本.而只有建 ...
- 图解数据结构树之AVL树
AVL树(平衡二叉树): AVL树本质上是一颗二叉查找树,但是它又具有以下特点:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树.在AVL树中任何节点的两个子 ...
- 二叉搜索树的平衡--AVL树和树的旋转(图解)
二叉搜索树只有保持平衡时其查找效率才会高. 要保持二叉搜索树的平衡不是一件易事.不过还是有一些非常经典的办法可以做到,其中最好的方法就是将二叉搜索树实现为AVL树. AVL树得名于它的发明者 G.M. ...
- 图解:平衡二叉树,AVL树
学习过了二叉查找树,想必大家有遇到一个问题.例如,将一个数组{1,2,3,4}依次插入树的时候,形成了图1的情况.有建立树与没建立树对于数据的增删查改已经没有了任何帮助,反而增添了维护的成本.而只有建 ...
- 二叉树之AVL树的平衡实现(递归与非递归)
这篇文章用来复习AVL的平衡操作,分别会介绍其旋转操作的递归与非递归实现,但是最终带有插入示例的版本会以递归呈现. 下面这张图绘制了需要旋转操作的8种情况.(我要给做这张图的兄弟一个赞)后面会给出这八 ...
- AVL树平衡旋转详解
AVL树平衡旋转详解 概述 AVL树又叫做平衡二叉树.前言部分我也有说到,AVL树的前提是二叉排序树(BST或叫做二叉查找树).由于在生成BST树的过程中可能会出现线型树结构,比如插入的顺序是:1, ...
- AVL树(查找、插入、删除)——C语言
AVL树 平衡二叉查找树(Self-balancing binary search tree)又被称为AVL树(AVL树是根据它的发明者G. M. Adelson-Velskii和E. M. Land ...
- 算法与数据结构(十一) 平衡二叉树(AVL树)
今天的博客是在上一篇博客的基础上进行的延伸.上一篇博客我们主要聊了二叉排序树,详情请戳<二叉排序树的查找.插入与删除>.本篇博客我们就在二叉排序树的基础上来聊聊平衡二叉树,也叫AVL树,A ...
随机推荐
- 搜索引擎如何检索结果:Python和spaCy信息提取简介
概览 像Google这样的搜索引擎如何理解我们的查询并提供相关结果? 了解信息提取的概念 我们将使用流行的spaCy库在Python中进行信息提取 介绍 作为一个数据科学家,在日常工作中,我严重依赖搜 ...
- Java 泛型数组问题
Java中不支持泛型数组, 以下代码会编译报错:generic array creation ArrayList<Integer>[] listArr = new ArrayList< ...
- redis的使用及配置
linux环境下redis启动和管理 在redis根目录下执命令 快捷启动默认端口 ./redis-server ../redis.conf 启动redis管理端 ./redis-cli 清理缓存命令 ...
- sql 模块sqllit
1.创建数据库表 面对 SQLite 数据库,我们之前熟悉的 SQL 指令都可以用: >>> create_table = "create table books (tit ...
- python字典(dict)
1.字典dict定义 初始化 key-value键值对的数据的集合,可变.无序.key不重复(哈希.唯一) 1> d = dict() 或者 d = {} # -*- coding:utf-8 ...
- RFID 有源,半源和无源的区别
RFID电子标签是由标签.解读器和数据传输和处理系统组成.内存带有天线的芯片,芯片中存储有能够识别目标的信息,主要作用都是为了识别货物.(更具体的自行搜索,本文单独讲三种的区别) RFID分为三种 有 ...
- 掌握使用gitlab ci构建Android包的正确方式
最近公司在做移动端的项目,自然而然的需要搭建打包的环境.本来计划用Jenkins的,但是发现在gitlab上创建完项目后,提示去配置pipeline,于是决定用gitlab去尝试下,毕竟我觉得Jenk ...
- Redis 哨兵模式(Sentinel)
上一篇我们介绍了 redis 主从节点之间的数据同步复制技术,通过一次全量复制和不间断的命令传播,可以达到主从节点数据同步备份的效果,一旦主节点宕机,我们可以选择一个工作正常的 slave 成为新的主 ...
- 微信小程序wx:for隐藏遍历的最后一个元素
微信小程序开发时有时会需要从wx:for遍历的元素中选取最后一个来进行相关操作,以下方法以隐藏最后一个元素为例 index==list.length-1 通过获取列表的总长度减一来得到最后一个元素是最 ...
- Vue-cli2.0 第3节 解读Vue-cli模板
Vue-cli2.0 第3节 解读Vue-cli模板 目录 Vue-cli2.0 第3节 解读Vue-cli模板 第3节 解读Vue-cli模板 1. npm run build命令 2. main. ...