手写AVL平衡二叉搜索树
手写AVL平衡二叉搜索树
二叉搜索树的局限性
先说一下什么是二叉搜索树,二叉树每个节点只有两个节点,二叉搜索树的每个左子节点的值小于其父节点的值,每个右子节点的值大于其左子节点的值。如下图:
二叉搜索树,顾名思义,它的搜索效率很高,可以达到O(logn)。但这是理想状况下的,即上图所示。实际上,由于插入顺序的原因,形成的二叉搜索树并不会像上图这样“工整”,最坏的情况的下,甚至可能会退化成链表了,如下图:
这显然不是我们想要看的结果,那么我们必须要引入一套机制来避免这种事情的发生,也就是让二叉搜索树带上平衡条件。
AVL平衡二叉搜索树
几个基本概念
叶子节点:既没有左子节点,也没有右左子节点的节点就是叶子节点。
树的高度:叶子节点的高度为1,空节点的高度是-1,父节点的高度是其两个子树较高一棵子树的高度加一。
平衡条件:每一个节点的左子树与右子树的高度差不超过1。
核心思想
因为AVL平衡二叉搜索树,父节点的两颗子树的高度差不能超过1。在AVL平衡二叉树种,采用旋转的机制来使不满足平衡条件的二叉树重新回到满足平衡条件的状态。在二叉搜索树中,需要被平衡的情况可以分为两大类总共四种情况,
- 单旋转
- 左旋转
- 右旋转
- 双旋转
- 先左旋,再右旋
- 先右旋,再左旋
如下图所示:
通过图片的形式我们很容易就可以写出使二叉树回到满足平衡条件的代码
// 右旋转
public TreeNode rightRotate(TreeNode root) {
TreeNode temp1 = root.left;
TreeNode temp2 = temp1.right;
temp1.right = root;
root.left = temp2;
return temp1;
}
// 左旋转
public TreeNode leftRotate(TreeNode root) {
TreeNode temp1 = root.right;
TreeNode temp2 = temp1.left;
temp1.left = root;
root.right = temp2;
return temp1;
}
// 先右后左
public TreeNode rightLeftRotate(TreeNode root) {
root.right = rightRotate(root.right);
return leftRotate(root);
}
// 先左后右
public TreeNode leftRightRotate(TreeNode root) {
root.left = leftRotate(root.left);
return rightRotate(root);
}
我们必须再每一次插入节点后判断树是否需要平衡,也就是是否会出现两颗子树的高度差超过1的情况,首先编写一个可以计算出传入节点 高度的函数。
public int height(TreeNode root) {
if (root == null) {
return -1;
}
if (root.left == null && root.right == null) {
return 0;
}
return Math.max(height(root.right), height(root.left));
}
有了这个函数,我们就不仅可以判断是否出现需要平衡的情况,还可以判断需要平衡的情况是四种情况种的哪一种。
public TreeNode balance(TreeNode root) {
int l = height(root.left);
int r = height(root.right);
if (l - r >= 2) {
// rightRotate
if (height(root.left.left) - height(root.left.right) >= 1) {
// rightRotate
root = rightRotate(root);
} else if (height(root.left.right) - height(root.left.left) >= 1) {
// leftRightRotate
root = leftRightRotate(root);
}
} else if (r - l >= 2) {
// leftRotate
if (height(root.right.right) - height(root.right.left) >= 1) {
// leftRotate
root = leftRotate(root);
} else if (height(root.right.left) - height(root.right.right) >= 1){
root = rightLeftRotate(root);
}
}
return root;
}
以上就是AVL平衡二叉搜索树的精髓,并且已经用代码实现了。
完整代码
这是我完善后的功能相对完整的AVL二叉搜索平衡树。
class TreeNode {
int value;
TreeNode left;
TreeNode right;
int height;
public TreeNode(int value) {
this.value = value;
}
}
public class AVLBinarySearchTree {
public static void main(String[] args) {
AVLBinarySearchTree a = new AVLBinarySearchTree();
for (int i = 0; i < 10; i++) {
a.insert(i);
}
}
private TreeNode root;
private static final int ALLOWED_IMBALANCE = 1;
// 删除元素
public void remove(int value) {
root = remove(value, root);
}
// 检查是否包含某一元素,包含则返回该节点,不包含则返回null
public TreeNode contain(int value) {
TreeNode temp = root;
if (temp == null) {
return temp;
}
while (temp.value != value) {
if (value > temp.value) {
temp = temp.right;
} else if (value < temp.value) {
temp = temp.left;
}
}
return temp;
}
// 删除指定子树上的指定元素
private TreeNode remove(int value, TreeNode abn) {
if (abn == null) {
return abn;
}
if (value > abn.value) {
abn.right = remove(value, abn.right);
} else if (value < abn.value) {
abn.left = remove(value, abn.left);
} else {
if (abn.right == null && abn.left == null) {
abn = null;
return abn;
} else if (abn.right != null) {
abn.value = findMin(abn.right).value;
abn.right = remove(abn.value, abn.right);
} else {
abn.value = findMax(abn.left).value;
abn.left = remove(abn.value, abn.left);
}
}
return balance(abn);
}
// 找到指定子树最大值
private TreeNode findMax(TreeNode abn) {
if (abn == null) {
return null;
}
TreeNode temp = abn;
while (temp.right != null) {
temp = temp.right;
}
return temp;
}
// 找到指定子树最小值
private TreeNode findMin(TreeNode abn) {
if (abn == null) {
return null;
}
TreeNode temp = abn;
while (temp.left != null) {
temp = temp.left;
}
return temp;
}
// 插入节点
public void insert(int value) {
root = insert(value, root);
}
// 计算节点高度
private int height(TreeNode abn) {
if (abn == null) {
return -1;
}
return abn.height;
}
// 树的高度
public int height() {
return height(root);
}
// 插入节点
private TreeNode insert(int value, TreeNode abn) {
if (abn == null) {
return new TreeNode(value);
}
if (value > abn.value) {
abn.right = insert(value, abn.right);
} else if (value < abn.value) {
abn.left = insert(value, abn.left);
}
return balance(abn);
}
// 平衡不平衡的树
private TreeNode balance(TreeNode abn) {
if (height(abn.left) - height(abn.right) > ALLOWED_IMBALANCE) {
if (height(abn.left.left) >= height(abn.left.right)) {
abn = leftSingleRotate(abn);
} else if (height(abn.left.left) < height(abn.left.right)) {
abn = leftDoubleRotate(abn);
}
} else if (height(abn.right) - height(abn.left) > ALLOWED_IMBALANCE) {
if (height(abn.right.right) >= height(abn.right.left)) {
abn = rightSingleRotate(abn);
} else {
abn = rightDoubleRotate(abn);
}
}
abn.height = Math.max(height(abn.left), height(abn.right)) + 1;
return abn;
}
// 右单旋转
private TreeNode rightSingleRotate(TreeNode abn) {
TreeNode temp = abn;
abn = abn.right;
temp.right = abn.left;
abn.left = temp;
temp.height = Math.max(height(temp.right), height(temp.left)) + 1;
abn.height = Math.max(height(abn.right), temp.height) + 1;
return abn;
}
// 左单旋转
private TreeNode leftSingleRotate(TreeNode abn) {
TreeNode temp = abn;
abn = abn.left;
temp.left = abn.right;
abn.right = temp;
temp.height = Math.max(height(temp.right), height(temp.left)) + 1;
abn.height = Math.max(height(abn.right), temp.height) + 1;
return abn;
}
// 右双旋转
private TreeNode rightDoubleRotate(TreeNode abn) {
abn.right = leftSingleRotate(abn.right);
return rightSingleRotate(abn);
}
// 左双旋转
private TreeNode leftDoubleRotate(TreeNode abn) {
abn.left = rightSingleRotate(abn.left);
return leftSingleRotate(abn);
}
}
手写AVL平衡二叉搜索树的更多相关文章
- 二叉搜索树、AVL平衡二叉搜索树、红黑树、多路查找树
1.二叉搜索树 1.1定义 是一棵二叉树,每个节点一定大于等于其左子树中每一个节点,小于等于其右子树每一个节点 1.2插入节点 从根节点开始向下找到合适的位置插入成为叶子结点即可:在向下遍历时,如果要 ...
- AVL平衡二叉搜索树原理及各项操作编程实现
C语言版 #include<stdio.h> #include "fatal.h" struct AvlNode; typedef struct AvlNode *Po ...
- 【算法学习】AVL平衡二叉搜索树原理及各项操作编程实现(C语言)
#include<stdio.h> #include "fatal.h" struct AvlNode; typedef struct AvlNode *Positio ...
- 看动画学算法之:平衡二叉搜索树AVL Tree
目录 简介 AVL的特性 AVL的构建 AVL的搜索 AVL的插入 AVL的删除 简介 平衡二叉搜索树是一种特殊的二叉搜索树.为什么会有平衡二叉搜索树呢? 考虑一下二叉搜索树的特殊情况,如果一个二叉搜 ...
- convert sorted list to binary search tree(将有序链表转成平衡二叉搜索树)
Given a singly linked list where elements are sorted in ascending order, convert it to a height bala ...
- 算法:非平衡二叉搜索树(UnBalanced Binary Search Tree)
背景 很多场景下都需要将元素存储到已排序的集合中.用数组来存储,搜索效率非常高: O(log n),但是插入效率比较低:O(n).用链表来存储,插入效率和搜索效率都比较低:O(n).如何能提供插入和搜 ...
- LeetCode 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树
第108题 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: 给定有序数组: [-10 ...
- 算法进阶面试题04——平衡二叉搜索树、AVL/红黑/SB树、删除和调整平衡的方法、输出大楼轮廓、累加和等于num的最长数组、滴滴Xor
接着第三课的内容和讲了第四课的部分内容 1.介绍二叉搜索树 在二叉树上,何为一个节点的后继节点? 何为搜索二叉树? 如何实现搜索二叉树的查找?插入?删除? 二叉树的概念上衍生出的. 任何一个节点,左比 ...
- 【数据结构与算法Python版学习笔记】树——平衡二叉搜索树(AVL树)
定义 能够在key插入时一直保持平衡的二叉查找树: AVL树 利用AVL树实现ADT Map, 基本上与BST的实现相同,不同之处仅在于二叉树的生成与维护过程 平衡因子 AVL树的实现中, 需要对每个 ...
随机推荐
- 嵌套div的onClick事件问题
嵌套div的onClick事件问题我在下面的代码中的外层div中加了onClick事件,这样当鼠标点击这个div的时候就会跳转了.但是我在图片上加了一些其他效果,所以当鼠标点击中间的img时不能触发跳 ...
- 大数据学习(03)——HDFS的高可用
高可用架构图 先上一张搜索来的图. 如上图,HDFS的高可用其实就是NameNode的高可用. 上一篇里,SecondaryNameNode是NameNode单节点部署才会有的角色,它只帮助NameN ...
- C语言复习(二)
引言: 不会将每一个部分都详述,只关注于一些自己认为重要的或常错的,若有不足,还望指出 switch()细节:括号内必须是整型或枚举类型:遇到break才会跳出:case包含的必须是常量 contin ...
- HttpRunner3源码阅读:7.响应后处理 response.py
response 上一篇说的client.py来发送请求,这里就来看另一个response.py,该文件主要是完成测试断言方法 可用资料 jmespath[json数据取值处理]: https://g ...
- Shell-05-函数
函数 函数定义 shell中函数的定义格式如下 [ function ] funname [()] { action; [return int;] } 说明: 1.可以带function fun() ...
- PostgreSQL 13.4的安装记录
PostgreSQL 13.4的安装记录 想着MySQL被Oracle给买了,总得做点别的准备不是,找了找别的开源的关系型数据库,貌似PostgreSQL的评价很不错,就试试先 因为是window10 ...
- 【ShardingSphere技术专题】「ShardingJDBC」SpringBoot之整合ShardingJDBC实现分库分表(JavaConfig方式)
前提介绍 ShardingSphere介绍 ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC.Sharding-Proxy和Shardin ...
- 软件研发中也有5S 管理?
在精益生产中,价值流是贯穿生产全程的关键要素,标准化作业是实现生产线同步的关键工具,而生产现场的5S 管理则是管理一切生产要素的基础,所以我们将5S 称为精益的基础并不为过.5S 管理不仅可以应用到车 ...
- spring-cloud-sleuth+zipkin追踪服务
1, 父Maven pom 文件 <parent> <groupId>org.springframework.boot</groupId> <artifact ...
- 堆排序——Java实现
一.堆排序 堆排序(Heap Sort)是指利用堆这种数据结构所设计的一种排序算法.堆是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点. 二.堆 什 ...