平衡二叉树(Self-balancing binary search tree)之AVL树

本文介绍了AVL树作为平衡二叉搜索树的基础概念,阐述了其出现的原因,即解决普通二叉排序树查询效率低下的问题。详细解释了AVL树的平衡条件及维护平衡的四种旋转操作:左旋、右旋、先左后右旋和先右后左旋,结合具体例子和步骤展示了旋转过程。同时,强调了在添加和删除节点时需要维护平衡的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.基础

(基础)二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),也称二叉搜索树

2.AVL树出现的背景

(AVL树出现的背景)问题分析:
数组 {1, 2, 3, 4, 5, 6} ,对应的二叉排序树(BST)的问题所在
(1)左子树全部为空,从形式上看,更像一个单链表
(2)插入速度没有影响
(3)查询速度明显降低(因为需要依次比较),不能发挥BST的优势,因为每次还需要比较左子树,查询速度比单链表还慢

3.优化演变,解决BST查询带来的问题

(由基础优化演变而来,解决BST查询带来的问题)AVL树(以发明者G.M.Adelson-Velsky和E.M.Landis的名字命名),又称平衡二叉搜索树(Self-balancing binary search tree),也称平衡二叉树
AVL树特点:
(1)本身是一棵二叉排序树
(2)带平衡条件:每个结点的左右子树的高度差的绝对值不超过1,最多为1
AVL树本质就是带平衡功能的二叉排序树

平衡二叉树的实现方式有红黑树(算法)、AVL(算法)、替罪羊树、Treap、伸展树等

4.什么时候需要维护平衡二叉树的平衡?

二叉树进行节点的 添加删除 的时候,都会破坏平衡二叉树的平衡,所以在二叉树添加节点完毕之后 与 二叉树删除节点完毕之后,都需要重新维护平衡二叉树的平衡

5.维护平衡二叉树平衡的方式之一

单向旋转之左旋转

添加一个节点之后,如果存在二叉树的任意一个节点的右子树的高度 减去 左子树的高度 所得的差大于 1 ,则需要把当前的二叉树通过左旋转的方式维护成平衡二叉树,即AVL树(递归的方式保证了任意一个节点的左右子树的高度差的绝对值不超过1)

左旋转的步骤

(1)创建一个新节点 newNode ,新节点的值等于当前节点的值(由于添加节点的代码存在递归,注意分析 当前节点 会有不同的指向)
(2)把新节点的左子树指向当前节点的左子树
newNode.left = this.left
(3)把新节点的右子树指向当前节点的右子树的左子树
newNode.right = this.right.left
(4)把当前节点的值设置为其右子节点的值
this.value = this.right.value
(5)把当前节点的右子树指向其右子树的右子树
this.right = this.right.right
(6)把当前节点的左子树指向新节点
this.left = newNode

图解左旋转的步骤

使用数组 {4, 3, 6, 5, 7, 8} 构造平衡二叉树的过程中,在添加 8 之前,二叉树中的任意一个节点的左右子树的高度差的绝对值不超过 1 ,即为 AVL树,当 添加 8 之后,得到如下二叉树,此时以 4 作为当前节点,它的右子树高度为 3 , 它的左子树高度为 1 ,即 3 - 1 = 2 > 1 ,该二叉树就不再是一棵平衡二叉树了,通过左旋转维护成平衡二叉树

 (1)创建一个新节点 newNode ,新节点的值等于当前节点的值(由于添加节点的代码存在递归,注意分析 当前节点 会有不同的指向)

(2)把新节点的左子树指向当前节点的左子树
newNode.left = this.left


(3)把新节点的右子树指向当前节点的右子树的左子树
newNode.right = this.right.left


(4)把当前节点的值设置为其右子节点的值
this.value = this.right.value


(5)把当前节点的右子树指向其右子树的右子树
this.right = this.right.right


(6)把当前节点的左子树指向新节点
this.left = newNode 

最后通过左旋转得到的平衡二叉树,即AVL树,如下

6.维护平衡二叉树平衡的方式之二

单向旋转之右旋转

添加一个节点之后,如果存在二叉树的任意一个节点的左子树的高度 减去 右子树的高度 所得的差大于 1 ,则需要把当前的二叉树通过右旋转的方式维护成平衡二叉树,即AVL树(递归的方式保证了任意一个节点的左右子树的高度差的绝对值不超过1)

右旋转的步骤

(1)创建一个新节点 newNode ,新节点的值等于当前节点的值(由于添加节点的代码存在递归,注意分析 当前节点 会有不同的指向)
(2)把新节点的右子树指向当前节点的右子树
newNode.right = this.right
(3)把新节点的左子树指向当前节点的左子树的右子树
newNode.left = this.left.right
(4)把当前节点的值设置为其左子节点的值
this.value = this.left.value
(5)把当前节点的左子树指向其左子树的左子树
this.left = this.left.left
(6)把当前节点的右子树指向新节点
this.right= newNode

图解右旋转的步骤

使用数组 {10, 12, 8, 9, 7, 6} 构造平衡二叉树的过程中,在添加 6 之前,二叉树中的任意一个节点的左右子树的高度差的绝对值不超过 1 ,即为 AVL树,当 添加 6 之后,得到如下二叉树,此时以 10 作为当前节点,它的左子树高度为 3 , 它的右子树高度为 1 ,即 3 - 1 = 2 > 1 ,该二叉树就不再是一棵平衡二叉树了,通过右旋转维护成平衡二叉树

(1)创建一个新节点 newNode ,新节点的值等于当前节点的值(由于添加节点的代码存在递归,注意分析 当前节点 会有不同的指向&#

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值