第八课 常见的二叉树:基于二叉搜索树的平衡二叉树之AVL树

1 平衡二叉树的定义

平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。平衡二叉树的常用算法有红黑树、AVL树等。在平衡二叉搜索树中,我们可以看到,其高度一般都良好地维持在O(log2n),大大降低了操作的时间复杂度。

2 平衡和不平衡

平衡因子:左右孩子节点的高度差
节点的高度:叶子节点=0,没有的计为-1

(1)平衡的二叉树
A的平衡因子=0-0=0
在这里插入图片描述
(2)不平衡的二叉树
A的平衡因子=1-(-1)=2
在这里插入图片描述

3 常见的平衡二叉树

3.1 AVL

3.1.1 定义

在计算机科学中,AVL树是最先发明的自平衡二叉查找树,所以他是基于二叉搜索树的平衡二叉树。AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 “An algorithm for the organization of information” 中发表了它。

3.1.2 维护平衡

这里以插入操作为例,分四种情况讨论。
(1)LL:向当前节点的左子树的左孩子中插入新节点导致不平衡,需要将当前节点右旋
在这里插入图片描述
(2)RR:向当前节点的右子树的右孩子中插入新节点导致不平衡,需要将当前节点左旋

在这里插入图片描述
(3)LR: 向当前节点的左子树的右孩子中插入新节点导致不平衡,需要先将当前节点的左子树左旋,再将当前节点右旋

在这里插入图片描述
(4)RL:向当前节点的右子树的左孩子中插入新节点导致不平衡,需要先将当前节点的右子树右旋,再将当前节点左旋
在这里插入图片描述

3.1.3代码实现

算法实现基于二叉搜索树,这里只讲解插入删除,其他的和二叉搜索树一样。

public class AvlTree<E elefttends Comparable<E>>{
	private class Node{
		public E e;
		public Node left;
		public Node right;
		public int height;

		public Node(E e){
			this.e = e;
			this.left = null;
			this.right = null;
			this.height = 1;
		}
	}

	private Node root;
	private int size;

	public AvlTree(){
		root=null;
		size=0;
	}
	
	/**
	 * 获取某一结点的高度
	 * @param node
	 * @return
	 */
	private int getHeight(Node node){
		if(node==null){
			return 0;
		}
		return node.height;
	}
	
	public int getSize(){
		return size;
	}
	public boolean isEmptnode(){
		return size == 0;
	}
	
	/**
	 * 获取节点的平衡因子
	 * @param node
	 * @return
	 */
	private int getBalanceFactor(Node node){
		if(node==null){
			return 0;
		}
		return getHeight(node.left)-getHeight(node.right);
	}
	
	/**
	 * 判断树是否为平衡二叉树
	 * @param node
	 * @return
	 */
	public boolean isBalanced(){
		return isBalanced(root);
	}
	
	/**
	 * 判断该节点是否平衡
	 * @param node
	 * @return
	 */
	private boolean isBalanced(Node node){
		if(node==null){
			return true;
		}
		int balanceFactornode = Math.abs(getBalanceFactor(node));
		if(balanceFactornode>1){
			return false;
		}
		return isBalanced(node.left)&&isBalanced(node.right);
	}
	
	/**
	 * 右旋LL
	 * @param node
	 * @return
	 */
	private Node rightRotate(Node node){
		Node l = node.left;
		Node lr = left.right;
		l.right = node;
		node.left = lr;
		//更新height
		node.height = Math.max(getHeight(node.left),getHeight(node.right))+1;
		l.height = Math.max(getHeight(l.left),getHeight(l.right))+1;
		return l;
	}
	/**
	 * 左旋RR
	 * @param node
	 * @return
	 */
	private Node leftRotate(Node node){
		Node r = node.right;
		Node rl = r.left;
		r.left = node;
		node.right = rl;
		//更新height
		node.height = Math.max(getHeight(node.left),getHeight(node.right))+1;
		r.height = Math.max(getHeight(r.left),getHeight(r.right))+1;
		return r;
	}
	/**
	 * 向二分搜索树中添加新的元素
	 * @param e
	 * @return
	 */
	public void insert(E e){
		root = insert(root, e);
	}
	/**
	 * 向二分搜索树中添加新的元素,用递归实现
	 *@param node
	 * @param e
	 * @return
	 */
	private Node insert(Node node, E e){
		if(node == null){
			size ++;
			return new Node(e);
		}
		if(e.compareTo(node.e) < 0)
			node.left = insert(node.left, e);
		else if(e.compareTo(node.e) > 0)
			node.right = insert(node.right, e);
		//更新height
		node.height = 1+Math.max(getHeight(node.left),getHeight(node.right));
		//计算平衡因子
		int balanceFactor = getBalanceFactor(node);
		if(balanceFactor > 1 && getBalanceFactor(node.left)>0) {
			//右旋LL
			return rightRotate(node);
		}
		if(balanceFactor < -1 && getBalanceFactor(node.right)<0) {
			//左旋RR
			return leftRotate(node);
		}
		//LR
		if(balanceFactor > 1 && getBalanceFactor(node.left) < 0){
			node.left = leftRotate(node.left);
			return rightRotate(node);
		}
		//RL
		if(balanceFactor < -1 && getBalanceFactor(node.right) > 0){
			node.right = rightRotate(node.right);
			return leftRotate(node);
		}
		return node;
	}

	
	/**
	 * 从二分搜索树中删除元素
	 * @param e
	 * @return
	 */
	public E delete(E e){
		Node node = getNode(root, e);
		if(node != null){
			root = delete(root, e);
			return node.e;
		}
		return null;
	}
	
	/**
	 * 从二分搜索树中删除元素,这里用递归实现
	 *@param node
	 * @param e
	 * @return
	 */
	private Node delete(Node node, E e){

		if( node == null )
			return null;
		Node retNode;
		if( e.compareTo(node.e) < 0 ){
			node.left = delete(node.left , e);
			retNode = node;
		}
		else if(e.compareTo(node.e) > 0 ){
			node.right = delete(node.right, e);
			retNode = node;
		}
		else{   
			// 待删除节点左子树为空的情况
			if(node.left == null){
				Node rightNode = node.right;
				node.right = null;
				size --;
				retNode = rightNode;
			}
			// 待删除节点右子树为空的情况
			else if(node.right == null){
				Node leftNode = node.left;
				node.left = null;
				size --;
				retNode = leftNode;
			}else {
				// 待删除节点左右子树均不为空的情况
				// 找到比待删除节点大的最小节点, 即待删除节点右子树的最小节点
				//getSuccessor这个方法可以参考上一篇BinarySearchTree里的,一样的
				Node successor = getSuccessor(node);
				successor.right = delete(node.right, successor.e);
				successor.left = node.left;

				node.left = node.right = null;

				retNode = successor;
			}
		}
		if(retNode==null)
			return null;
		
		//更新height
		retNode.height = 1+Math.max(getHeight(retNode.left),getHeight(retNode.right));
		//计算平衡因子
		int balanceFactor = getBalanceFactor(retNode);
		if(balanceFactor > 1 && getBalanceFactor(retNode.left)>=0) {
			//右旋LL
			return rightRotate(retNode);
		}
		if(balanceFactor < -1 && getBalanceFactor(retNode.right)<=0) {
			//左旋RR
			return leftRotate(retNode);
		}
		//LR
		if(balanceFactor > 1 && getBalanceFactor(retNode.left) < 0){
			node.left = leftRotate(retNode.left);
			return rightRotate(retNode);
		}
		//RL
		if(balanceFactor < -1 && getBalanceFactor(retNode.right) > 0){
			node.right = rightRotate(retNode.right);
			return leftRotate(retNode);
		}
		return retNode;
	}
		
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Java封神之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值