平衡二叉树(AVL树)

本文来自:https://blog.zhenlanghuo.top/2017/08/22/AVL%E5%B9%B3%E8%A1%A1%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E5%AE%9E%E7%8E%B0/

普通的二叉查找树在插入有序的数据的时候会退化为链表,查找的时间复杂度退化为O(n)。而平衡二叉树在插入数据的时候一直保持二叉树的平衡,从而保证查找的时间复杂度维持在O(logn)。

平衡二叉树的定义

一棵平衡二叉树是其每个结点的左子树和右子树的高度最多相差1的二叉查找树(空树的高度为-1)。

二叉树的高度——当前结点到叶子结点的最长路径

四种旋转的情况
若平衡二叉树种某个结点的左子树和右子树的高度相差大于1,该树就是失衡了,该结点称为失衡点,就要通过旋转来保持二叉树的平衡。

一共分四种情况导致结点失衡:

  • 在结点的左孩子的左子树中插入数据(LL)
  • 在结点的左孩子的右子树中插入数据(LR)
  • 在结点的右孩子的左子树中插入数据(RL)
  • 在结点的右孩子的右子树中插入数据(RR)

第1和4种情况是对称的,可用单旋来解决,而第2和3种情况也是对称的,要用双旋来解决。

LL型(左孩子的左子树)通过右旋解决

对于LL型的情况,要使用右旋来解决,将失衡点右旋到其左孩子的右孩子的位置,失衡点的左子树更新为其原来左孩子的右子树。
在这里插入图片描述
在这里插入图片描述
RR型(右孩子的右子树)通过左旋解决
对于RR型的情况,要使用左旋来解决,将失衡点左旋到其右孩子的左孩子的位置,失衡点的右子树更新为其原来右孩子的左子树。
在这里插入图片描述
在这里插入图片描述
LR型(左孩子的右子树)通过先左旋再右旋解决
对于LR型的情况,要使用先对失衡点的左孩子进行左旋,然后再对失衡点进行右旋来解决。
在这里插入图片描述
在这里插入图片描述
RL型(右孩子的左子树)通过先右旋再左旋解决
对于RL型的情况,要使用先对失衡点的右孩子进行右旋,然后再对失衡点进行左旋来解决。
在这里插入图片描述
在这里插入图片描述

3、代码实现

3.1 AVLNode

public class AVLNode<T extends Comparable<T>> {
   
	
	public AVLNode<T> left;
	
	public AVLNode<T> right;
	
	public T data;
	
	//当前结点的高度
	public int height;
	
	public AVLNode(T data) {
   
		this.data = data;
	}
	
}

AVLNode中一定要保存结点的高度,并在高度有变化的时候进行更新,我看过有一些简单的实现,在结点的数据结构中没有记录结点的高度,每次判断是否平衡的时候都要重新递归计算结点的高度,这样的做法效率很低

3.2 四种情况的旋转操作

  /**
 * 右旋操作(针对LL型的情况)
 * @param unbalance
 * @return
 */
public AVLNode<T> singleRotateRight(AVLNode<T> unbalance) {
   
	//失衡点的左孩子
	AVLNode<T> leftNode = unbalance.left;
	
	//将失衡点的左孩子更新为leftNode的右子树
	unbalance.left = leftNode.right;
	//失衡点右旋,变成leftNode的右孩子
	leftNode.right = unbalance;
	
	//更新leftNode和失衡点的高度
	unbalance.height = Math.max(height(unbalance.left),height(unbalance.right)) + 1;
	leftNode.height = Math.max(height(leftNode.left),unbalance.height) + 1;
	
	return leftNode;
}

/**
 * 左旋操作(针对RR型的情况)
 * @param unbalance
 * @return
 */
public AVLNode<T> singleRotateLeft(AVLNode<T> unbalance) {
   
	//失衡点的右孩子
	AVLNode<T> rightNode = unbalance.right;
	
	//将失衡点的右孩子更新为rightNode的左子树
	unbalance.right = rightNode.left;
	//失衡点左旋,变成rightNode的左孩子
	rightNode.
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值