手写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树的实现中, 需要对每个 ...
随机推荐
- 使用html2canvas.js将HTML生成图片
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- HCIA-物理层
OSI七层模型 应-->表-->会-->传-->网-->数-->物理层 TCP/IP四层模型 两个主导协议 -->工业标准 应-->传-->网-- ...
- 化学专业大二转战Android开发,终于拥有了鹅厂暑期实习offer
我是双非学校,应用化学专业,一年前我大二,现在我大三.一年前我两手空空,现在我拥有了鹅厂暑期实习的offer. 虽然结果是好的,但我春招实习的道路远没有这么简单和辉煌,它是无比坎坷的:每个人应该量力而 ...
- Microservices==>Service Mesh==>Serverless,走马观花
[0] 始有道 话说图灵开天辟地,冯.诺伊曼造石补天! 始有道道生ML Machine LanguageML生汇编 assembler汇编生编译器 compiler编译器生PL Programming ...
- 熬夜肝了一份 C++/Linux 开发学习路线
大家好,我是帅地. 之前写过几篇学习路线的文章 前端开发学习路线 Java 后端开发学习路线 一般开发岗主流的就是 Java 后台开发,前端开发以及 C++ 后台开发,现在 Go 开发也是越来越多了, ...
- 关于shell脚本——条件测试、if语句、case语句
目录 一.条件测试 1.1.表达说明 1.2.test命令 文件测试 1.3.整数值比较 1.4.字符串比较 1.5.逻辑测试 二.if语句 2.1.单分支结构 2.2.双分支结构 2.3.多分支结构 ...
- 011 FPGA千兆网TCP通信【转载】
一.LWIP 首先通过上面的简单分析,我们应该很清楚一件事:TCP协议很复杂,光握手过程就需要"三次握手.四次挥手"的复杂过程,不是特别适合FPGA的纯逻辑实现,因为用FPGA实现 ...
- 5 秒克隆声音「GitHub 热点速览 v.21.34」
作者:HelloGitHub-小鱼干 本周特推的 2 个项目都很好用,Realtime-Voice-Clone-Chinese 能让你无需开启变声音,即可获得一个特定声音的语音.这个声音可以是你朋友的 ...
- 题解 P3322 [SDOI2015]排序
题解 仔细审题,我们会发现 小 \(A\) 认为两个操作序列不同,当且仅当操作个数不同,或者至少一个操作不同(种类不同或者操作位置不同). 所以,对于一种操作,不管是交换哪两段,都算作同一种操作,只会 ...
- SpringCloud升级之路2020.0.x版-22.Spring Cloud LoadBalancer核心源码
本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 经过上一节的详细分 ...