当前位置:网站首页>AVL 平衡二叉搜索树
AVL 平衡二叉搜索树
2022-07-01 15:42:00 【颜 然】
二叉搜索树(BST)虽能缩短查找效率,但如果数据有序或接近有序,BST将退化为单支树,此时查找元素就相当于在顺序表中搜索元素,效率低下。
那么此时如果能保证每个结点的左右子树高度差的绝对值不超过1,就可以降低树的高度,从而减少平均搜索长度。所以AVL带着这个使命诞生了。
一、AVL
在二叉树中,如果每个结点的子树的高度差距为0、1或-1,则称这棵树是平衡二叉树,即AVL。
二、平衡二叉树
执行插入或删除操作后如果导致了AVL的不平衡,那么我们需要执行旋转操作来重新平衡这棵树。旋转操作主要有LL、RR、LR、RL四种类型。
1、LL
向左子树中的左孩子插入新结点后导致不平衡,此时需要右旋操作:

旋转后平衡二叉树将B看作新root, 将E结点与A.left相连,再将A与B.right相连,最后得到新的AVL。
private void balanceLL(AVLTreeNode<E> A, TreeNode<E> parentOfA){
TreeNode<E> B = A.left;
if(A == root){
root = B;
}else{
if(parentOfA.left == A){
parentOfA.left = B;
}else{
parentOfA.right = B;
}
}
A.left = B.right;
B.right = A;
updateHeight((AVLTreeNode<E>) A);
2、RR
和LL相反,向右子树中的右孩子插入新结点后导致的不平衡,此时需要左旋操作:

private void balanceRR(TreeNode<E> A, TreeNode<E> parentOfA){
TreeNode<E> B =A.right;
if(A == root){
root = B;
}else{
if(parentOfA.left == A){
parentOfA.left = B;
}else{
parentOfA.right = B;
}
}
A.right = B.left;
B.left = A;
updateHeight((AVLTreeNode<E>)A);
updateHeight((AVLTreeNode<E>)B);
}3、LR
左儿子左旋,根结点右旋:

private void balanceLR(TreeNode<E> A, TreeNode<E> parentOfA){
TreeNode<E> B = A.left;
TreeNode C = B.right;
if(A == root){
root = C;
}else{
if(parentOfA.left == A){
parentOfA.left = C;
}else {
parentOfA.right = C;
}
}
A.left = C.right;
B.right = C.left;
C.left = B;
C.right = A;
updateHeight((AVLTreeNode<E>)A);
updateHeight((AVLTreeNode<E>)B);
updateHeight((AVLTreeNode<E>)C);
}4、RL
右儿子右旋,根结点左旋:

private void balanceRL(TreeNode<E> A, TreeNode<E> parentOfA){
TreeNode<E> B = A.right;
TreeNode<E> C = B.left;
if(A == root){
root = C;
}else{
if(parentOfA.left == A){
parentOfA.left = C;
}else{
parentOfA.right = C;
}
}
A.right = C.left;
B.left = C.right;
C.left = A;
C.right = B;
updateHeight((AVLTreeNode<E>)A);
updateHeight((AVLTreeNode<E>)B);
updateHeight((AVLTreeNode<E>)C);
}三、Java实现AVLTree类
AVLTree类继承BST类。
public class AVLTree<E extends Comparable<E>> extends BST<E>{
public AVLTree() {
}
public AVLTree(E[] objects) {
super(objects);
}
// 插入方法和BST中的方法一样,只不过每次添加后需要检查平衡
@Override
public boolean insert(E e){
boolean success = super.insert(e);
if(!success){
return false;
}else{
balancePath(e); // 检查是否需要平衡操作
}
return true;
}
private void updateHeight(AVLTreeNode<E> node){
if(node.left == null && node.right == null){
node.height = 0;
}else if(node.left == null){
node.height = 1 + ((AVLTreeNode<E>)(node.right)).height;
}else if(node.right == null){
node.height = 1 + ((AVLTreeNode<E>)(node.left)).height;
}else
node.height = 1 + Math.max(((AVLTreeNode<E>)(node.right)).height,((AVLTreeNode<E>)(node.left)).height);
}
// 平衡一条路径上的结点
private void balancePath(E e){
java.util.ArrayList<TreeNode<E>> path = path(e); // 获取包含e的结点到根结点的路径
for(int i = path.size() - 1; i >= 0; i--){
AVLTreeNode<E> A = (AVLTreeNode<E>)(path.get(i));
updateHeight(A); // 更新高度
AVLTreeNode<E> parentOfA = (A == root) ? null : (AVLTreeNode<E>)(path.get(i - 1));
switch(balanceFactor(A)){ // 检查平衡因子,检查是否需要旋转
case -2 :
if(balanceFactor((AVLTreeNode<E>)A.left) <= 0){
balanceLL(A,parentOfA);
}else{
balanceLR(A,parentOfA);
}
break;
case +2 :
if(balanceFactor((AVLTreeNode<E>)A.right) >= 0){
balanceRR(A, parentOfA);
}else{
balanceRL(A, parentOfA);
}
}
}
}
private int balanceFactor(AVLTreeNode<E> node){
if(node.left == null){
return -node.height;
}else if(node.left == null){
return +node.height;
}else
return ((AVLTreeNode<E>)node.right).height - ((AVLTreeNode<E>)node.left).height;
}
private void balanceLL(AVLTreeNode<E> A, TreeNode<E> parentOfA){
TreeNode<E> B = A.left;
if(A == root){
root = B;
}else{
if(parentOfA.left == A){
parentOfA.left = B;
}else{
parentOfA.right = B;
}
}
A.left = B.right;
B.right = A;
updateHeight((AVLTreeNode<E>) A);
updateHeight((AVLTreeNode<E>) B);
}
private void balanceLR(TreeNode<E> A, TreeNode<E> parentOfA){
TreeNode<E> B = A.left;
TreeNode C = B.right;
if(A == root){
root = C;
}else{
if(parentOfA.left == A){
parentOfA.left = C;
}else {
parentOfA.right = C;
}
}
A.left = C.right;
B.right = C.left;
C.left = B;
C.right = A;
updateHeight((AVLTreeNode<E>)A);
updateHeight((AVLTreeNode<E>)B);
updateHeight((AVLTreeNode<E>)C);
}
private void balanceRR(TreeNode<E> A, TreeNode<E> parentOfA){
TreeNode<E> B =A.right;
if(A == root){
root = B;
}else{
if(parentOfA.left == A){
parentOfA.left = B;
}else{
parentOfA.right = B;
}
}
A.right = B.left;
B.left = A;
updateHeight((AVLTreeNode<E>)A);
updateHeight((AVLTreeNode<E>)B);
}
private void balanceRL(TreeNode<E> A, TreeNode<E> parentOfA){
TreeNode<E> B = A.right;
TreeNode<E> C = B.left;
if(A == root){
root = C;
}else{
if(parentOfA.left == A){
parentOfA.left = C;
}else{
parentOfA.right = C;
}
}
A.right = C.left;
B.left = C.right;
C.left = A;
C.right = B;
updateHeight((AVLTreeNode<E>)A);
updateHeight((AVLTreeNode<E>)B);
updateHeight((AVLTreeNode<E>)C);
}
// 和BST中的删除方法一样,只不过需要判断下是否平衡
@Override
public boolean delete(E element){
if (root == null) {
return false;
}
TreeNode<E> parent = null;
TreeNode<E> current = root;
while(current != null){
if(element.compareTo(current.element) < 0){
parent = current;
current = current.left;
}else if(element.compareTo(current.element) > 0){
parent = current;
current = current.right;
}else break;
}
if(current == null){
return false;
}
if(current.left == null){
if(parent == null){
root = current.right;
}else {
if(element.compareTo(parent.element) < 0){
parent.left = current.right;
}else{
parent.right = current.right;
}
balancePath(parent.element);
}
}else{
TreeNode<E> parentOfRightMost = current;
TreeNode<E> rightMost = current.left;
while(rightMost.right != null){
parentOfRightMost = rightMost;
rightMost = rightMost.right;
}
current.element = rightMost.element;
if(parentOfRightMost.right == rightMost){
parentOfRightMost.right = rightMost.left;
}else{
parentOfRightMost.left = rightMost.left;
}
balancePath(parentOfRightMost.element);
}
size--;
return true;
}
protected static class AVLTreeNode<E> extends BST.TreeNode<E>{
protected int height = 0;
public AVLTreeNode(E e){
super(e);
}
}
}四、测试AVLTree类
public class TestAVLTree {
public static void main(String[] args){
AVLTree<Integer> tree = new AVLTree<Integer>(new Integer[]{25, 20 ,5});
System.out.print("After inserting 25,20,,5: ");
printTree(tree);
tree.insert(34);
tree.insert(50);
System.out.print("\nAfter inserting 34, 50 : ");
printTree(tree);
tree.insert(30);
System.out.print("\nAfter inserting 30 : ");
printTree(tree);
tree.insert(10);
System.out.print("\nAfter inserting 10 : ");
printTree(tree);
tree.delete(34);
tree.delete(30);
tree.delete(50);
System.out.print("\nAfter removing 34, 30, 50: ");
printTree(tree);
tree.delete(5);
System.out.print("\nAfter removing 5 : ");
printTree(tree);
System.out.print("\nTraverse the element in the tree: ");
for(Object e : tree){
System.out.print(e + " ");
}
}
public static void printTree(BST tree){
System.out.print("\nInorder (sorted) : ");
tree.inorder();
System.out.print("\nPostorder : ");
tree.postorder();
System.out.print("\nPreorder");
tree.preorder();
System.out.print("\nThe number of nodes is " + tree.getSize());
System.out.println();
}
}程序插入图示:

程序删除图示:

边栏推荐
- [video memory optimization] deep learning video memory optimization method
- 【云动向】6月上云新风向!云商店热榜揭晓
- What are the EN ISO 20957 certification standards for common fitness equipment
- 跨平台应用开发进阶(二十四) :uni-app实现文件下载并保存
- C#/VB.NET 合并PDF文档
- Survey of intrusion detection systems:techniques, datasets and challenges
- Stm32f4-tft-spi timing logic analyzer commissioning record
- Create employee data in SAP s/4hana by importing CSV
- RT-Thread Env 工具介绍(学习笔记)
- 摩根大通期货开户安全吗?摩根大通期货公司开户方法是什么?
猜你喜欢

STM32ADC模拟/数字转换详解

Zhang Chi Consulting: lead lithium battery into six sigma consulting to reduce battery capacity attenuation

Tensorflow team: we haven't been abandoned

你TM到底几点下班?!!!

Équipe tensflow: Nous ne sommes pas abandonnés

Phpcms background upload picture button cannot be clicked

Tiantou village, Guankou Town, Xiamen special agricultural products Tiantou Village special agricultural products ant new village 7.1 answer

【STM32-USB-MSC问题求助】STM32F411CEU6 (WeAct)+w25q64+USB-MSC Flash用SPI2 读出容量只有520KB
![[300 + selected interview questions from big companies continued to share] big data operation and maintenance sharp knife interview question column (III)](/img/cf/44b3983dd5d5f7b92d90d918215908.png)
[300 + selected interview questions from big companies continued to share] big data operation and maintenance sharp knife interview question column (III)

STM32F411 SPI2输出错误,PB15无脉冲调试记录【最后发现PB15与PB14短路】
随机推荐
SAP S/4HANA: 一条代码线,许多种选择
最新NLP赛事实践总结!
[stm32-usb-msc problem help] stm32f411ceu6 (Weact) +w25q64+usb-msc flash uses SPI2 to read out only 520kb
MySQL审计插件介绍
Reading notes of top performance version 2 (V) -- file system monitoring
Logical analysis of automatic decision of SAP CRM organization model
Preorder, inorder, follow-up of binary tree (non recursive version)
Qt+pcl Chapter 6 point cloud registration ICP series 3
她就是那个「别人家的HR」|ONES 人物
Pico, can we save consumer VR?
Wechat applet 02 - Implementation of rotation map and picture click jump
Survey of intrusion detection systems:techniques, datasets and challenges
《QT+PCL第九章》点云重建系列2
Tanabata confession introduction: teach you to use your own profession to say love words, the success rate is 100%, I can only help you here ~ (programmer Series)
[Cloudera][ImpalaJDBCDriver](500164)Error initialized or created transport for authentication
有些能力,是工作中学不来的,看看这篇超过90%同行
The newly born robot dog can walk by himself after rolling for an hour. The latest achievement of Wu Enda's eldest disciple
厦门灌口镇田头村特色农产品 甜头村特色农产品蚂蚁新村7.1答案
ThinkPHP advanced
使用swiper制作手机端轮播图