平衡二叉树Java语言实现

本文详细介绍了平衡二叉树(AVL-Tree)的概念及其在执行插入和删除操作后如何进行平衡操作,确保操作后的数仍然满足平衡二叉树的条件。通过具体的代码示例,展示了平衡二叉树在执行各种操作后的平衡调整过程,包括左单旋、左双旋、右单旋和右双旋四种常见情况。

作为二叉查找树的升级版,平衡二叉树(AVL-Tree)可以有效保障树的深度,防止因为插入操作的顺序和删除操作等导致二叉查找树左右过于不均衡,下面的代码也是书上的源码代码,稍微改动和增加了些。

内部节点AvlNode:

<span style="white-space:pre">	</span>/**
	 * Node of AVLTree
	 * @author LQC
	 *
	 * @param <AnyType> element extends Comparable
	 */
	private static class AvlNode<AnyType>{
		AnyType element;
		AvlNode lc;
		AvlNode rc;
		int height;
		
		AvlNode(AnyType x){
			this(x, null, null);
		}
		
		AvlNode(AnyType x, AvlNode _lc, AvlNode _rc){
			this.element = x;
			this.lc = _lc;
			this.rc = _rc;
			height = 0;
		}
	}

插入函数,

<span style="white-space:pre">	</span>/**
	 * Internal method to insert item to AVLTree
	 * @param x item to insert
	 * @param n the node that roots the subtree
	 * @return root of the subtree
	 */
	private AvlNode<AnyType> insert(AnyType x, AvlNode<AnyType> n){
		if(n == null)
			return new AvlNode(x, null, null);
		//insert
		int cr = x.compareTo(n.element);
		if(cr < 0){
			//insert
			n.lc = insert(x, n.lc);
			//need to balance
			if(getHeight(n.lc) - getHeight(n.rc) == 2){
				if(x.compareTo((AnyType) n.lc.element) < 0)
					n = rotateWithLeftChildren(n);
				else
					n = doubleRotateWithLeftChildren(n);
			}
		}
		else if(cr > 0){
			n.rc = insert(x, n.rc);
			if(getHeight(n.rc) - getHeight(n.lc) == 2){
				if(x.compareTo((AnyType) n.rc.element) > 0)
					n = rotateWithRightChildren(n);
				else
					n = doubleRotateWithRightChildren(n);
			}
		}
		
		n.height = Math.max(getHeight(n.lc), getHeight(n.rc)) + 1;
		
		return n;
	}

删除函数,

        /**
	 * Internal method to remove item from subtree 
	 * @param x
	 * @return
	 */
	private AvlNode<AnyType> remove(AnyType x, AvlNode<AnyType> n){
		if(n == null)
			return n;
		int cr = x.compareTo(n.element);
		if(cr < 0){
			n.lc = remove(x, n.lc);
			if(getHeight(n.rc) - getHeight(n.lc) == 2){
				// need to balance
				if(n.rc.lc == null)
					return rotateWithRightChildren(n);
				else
					return doubleRotateWithRightChildren(n);
			}
		}
		else if(cr > 0){
			n.rc = remove(x, n.rc);
			if(getHeight(n.lc) - getHeight(n.rc) == 2){
				// need to balance
				if(n.lc.rc == null){
					// roatate
					return rotateWithLeftChildren(n);
				}
				else
					return doubleRotateWithLeftChildren(n);
			}
		}
		else{
			if(n.lc != null && n.rc != null){
				AnyType m = findMin(n.rc).element;
				n.element = m;
				n.rc = remove(m, n.rc);
				
				return n;
			}
			else
				return n.lc == null ? n.rc : n.lc;
		}
		
		return n;
	}
平衡二叉树在执行插入和删除操作后,都要进行平衡操作,确保操作后的数仍然满足平衡二叉树的条件(左右子树高度相差不超过1),出现不平衡时大致可以分为四种情况。

1:左单旋。如注释中所示,K1的左子树过长,由于K3小于K2和K1,所以执行一次单旋操作即可

<span style="white-space:pre">	</span>/**
	 *    	K1            K2
	 *    K2     ->    K3     K1
	 *  k3
	 * @param n
	 * @return
	 */
	private AvlNode<AnyType> rotateWithLeftChildren(AvlNode<AnyType> n){
		AvlNode<AnyType> k1 = n;
		AvlNode<AnyType> k2 = n.lc;
		AvlNode<AnyType> k3 = n.lc.lc;
		
		k1.lc = k2.rc;
		k2.rc = k1;
		
		//set height
		k1.height = Math.max(getHeight(k1.lc), getHeight(k1.rc)) + 1;
		k2.height = Math.max(getHeight(k2.lc), getHeight(k2.rc)) + 1;
		
		return k2;
	}
2:左双旋。此时,左单旋不能解决问题,需要旋转两次,首先对K2进行左单旋,旋转之后变为第一种模式,因此对K1执行再一次左单选即可(代码如下another method)。也可以直接对K1,K2,K3的子树进行移动,代码如下所示。

<span style="white-space:pre">	</span>/**
	 *      K1             K3
	 *   K2       ->    K2     K1
	 *      K3
	 * @param n
	 * @return
	 */
	private AvlNode<AnyType> doubleRotateWithLeftChildren(AvlNode<AnyType> n){
		AvlNode<AnyType> k1 = n;
		AvlNode<AnyType> k2 = n.lc;
		AvlNode<AnyType> k3 = n.lc.rc;
		
		k2.rc = k3.lc;
		k1.lc = k3.rc;
		k3.lc = k2;
		k3.rc = k1;
		
		k1.height = Math.max(getHeight(k1.lc), getHeight(k1.rc)) + 1;
		k2.height = Math.max(getHeight(k2.lc), getHeight(k2.rc)) + 1;
		k3.height = Math.max(getHeight(k3.lc), getHeight(k3.rc)) + 1;
		
		// another method
		//k1.lc = rotateWithRightChildren(k2);
		//return rotateWithLeftChildren(k1);
		
		return k3;
	}
3:右单旋、右双旋和左单旋、左双旋是对称的,执行步骤基本类似,代码如下。

<span style="white-space:pre">	</span>/**
	 *     	K1               K2
	 *        K2    ->    K1     K3
	 *          K3
	 * @param n
	 * @return
	 */
	private AvlNode<AnyType> rotateWithRightChildren(AvlNode<AnyType> n){
		AvlNode<AnyType> k1 = n;
		AvlNode<AnyType> k2 = n.rc;
		
		k1.rc = k2.lc;
		k2.lc = k1;
		
		k1.height = Math.max(getHeight(k1.lc), getHeight(k1.rc)) + 1;
		k2.height = Math.max(getHeight(k2.lc), getHeight(k2.rc)) + 1;
		
		return k2;
	}
	
	/**
	 *     K1             K2
	 *        K3   ->  K1    K3
	 *     K2
	 * @param n
	 * @return
	 */
	private AvlNode<AnyType> doubleRotateWithRightChildren(AvlNode<AnyType> n){
		AvlNode<AnyType> k1 = n;
		AvlNode<AnyType> k3 = n.rc;
		AvlNode<AnyType> k2 = n.rc.lc;
		
		k1.rc = k2.lc;
		k3.lc = k2.rc;
		k2.lc = k1;
		k2.rc = k3;
		
		k1.height = Math.max(getHeight(k1.lc), getHeight(k1.rc)) + 1;
		k3.height = Math.max(getHeight(k3.lc), getHeight(k3.rc)) + 1;
		k2.height = Math.max(getHeight(k2.lc), getHeight(k2.rc)) + 1;
		
		// another method
		//k1.rc = rotateWithLeftChildren(k3);
		//return rotateWithRightChildren(k1);
		
		return k2;
	}
以上是平衡二叉树的插入和删除部分代码,经过初步测试暂时没有问题,如果有问题,也希望大家多多指出,多多交流。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值