AVL树

二叉排序树

  • 优点:既能够保证插入,删除节点的效率,同时也能兼顾查找的效率。
  • 缺点:当二叉树的节点倾向一边时,其查询性能就大打折扣了,几乎变成了链表。
    如图所示:在这里插入图片描述
    AVL树(平衡二叉树)就是来解决这个问题的。

AVL树

  • 具有的特性 :
    1. 与二叉查找树具有相同的特性
    2. 每个节点的左子树和右子树之间的高度差不能超过1

图一:是一颗平衡二叉树,它的左右子树的高度差为1。
在这里插入图片描述
图二:不是一颗平衡二叉树,因为值为3的这个节点的左子树的高度为2,右子树的高度为0,左右子树的高度差超过1。
在这里插入图片描述

  • 如何保证二叉树排序树是AVL树?
    1. 单旋转(左旋):该二叉排序树向右倾,称为右-右型,需要对其进行左旋才能让它变成AVL树。
      在这里插入图片描述
    2. 单旋转(右旋):该二叉排序树向左倾,称为左-左型,需要对其进行右旋才能让它变成AVL树。
      在这里插入图片描述
    3. 双旋转(先左再右):左-右型,先左旋转,再右旋转。
      在这里插入图片描述
  1. 双旋转(先右再左):右-左型,先右旋转,再左旋转。
    在这里插入图片描述
    小规律 :

     1、左-左型:做右旋。
     
     2、右-右型:做左旋转。
    
     3、左-右型:先做左旋,后做右旋。
    
     4、右-左型:先做右旋,再做左旋。
    

右旋转的步骤:( 如下图所示)

1.创建一个新节点,用来保存值为7节点的value
2.让值为7节点的左子树指向5节点的右子树
3.将7节点的值赋给5节点,并让7节点的左子树指向5节点的左子树(相当于把原来的7节点删除)
4.让新7节点的右子树指向新节点

在这里插入图片描述
代码实现 :

package AVLTree;

/**
 * AVL树要求每个节点的左子树和右子树的高度差不差过1
 * @author liuyang
 *
 */
public class AVLNode {
	
	//节点的值
	int value;
	//左子树
	AVLNode left;
	//右子树
	AVLNode right;
	
	public AVLNode(int v) {
		this.value = v;
	}
	
	//查询该节点的高度
	public int height() {
		return Math.max(left==null?0:left.height(), right==null?0:right.height())+1;
	}
	//查看该节点左子树的高度
	public int leftHeight() {
		if(left==null) {
			return 0;
		}
		return left.height();
	}
	//查看该节点右子树的高度
	public int rightHeight() {
		if(right==null) {
			return 0;
		}
		return right.height();
	}
	
	//添加节点
	public void add(AVLNode node) {
		
		//递归退出的条件
		if(node==null) {
			return;
		}
		//将添加的节点变成一颗二叉排序树
		if(node.value>this.value) {
			if(this.right!=null) {
				right.add(node);
			}else {
				right = node;
			}
		} else {
			if(this.left!=null) {
				left.add(node);
			}else {
				left = node;
			}
		}
		
		//检查是否是平衡二叉树
		//右旋转
		if( leftHeight()-rightHeight()>1 ) {
			//双旋转
			if(left!=null&&left.rightHeight()>left.leftHeight()) {
				//先左旋转
				left.leftRotate();
				//再右旋转
				this.rightRotate();
			}else { //单旋转
				this.rightRotate();
			}
			
		}//左旋转
		else if(rightHeight()-leftHeight()>1) {
			//双旋转
			if(right!=null&&right.rightHeight()>right.leftHeight()) {
				//先右旋转
				right.rightRotate();
				//再左旋转
				this.leftRotate();
			}else {//单旋转
				this.leftRotate();
			}
			
		}		
	}
	
	
	//右旋转
	private void rightRotate() {
		//先创建一个新节点,值等于该节点的value
		AVLNode node = new AVLNode(this.value);
		//让新节点的右子树指向这个节点的右子树
		node.right = this.right;
		//让新节点的左子树指向该节点左子树的右子树
		node.left = left.right;
		//将该节点的左子树的value赋给该节点
		this.value = left.value;
		//将该节点的左子树指向左子树的左子树
		this.left = left.left;
		//将该节点的右子树指向新的节点
		this.right = node;
	}
	
	//左旋转
	private void leftRotate() {
		//先创建一个新节点,值等于this.value
		AVLNode node = new AVLNode(this.value);
		node.left = this.left;
		node.right = right.left;
		this.value = right.value;
		this.right = right.right;
		this.left = node;
	}

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值