AVL树插入删除

AVL树是一种平衡二叉树,其每个节点的左右子树高度最多差1,空树高度定为-1,当左右的高度超过1,即失去了平衡,不是AVL树了。

private static class AVLNode<AnyType>{
	AVLNode (AnyType element)
		{this(element ,null,null);}
	AVLNode(AnyTape element,AVLNode<AnyType> left,AVLNode<AnyType> right){
		this.element = element;
		this.left = left;
		this.right = right;
	}
	AnyTape element;
	AVLNode<AnyType> left;
	AVLNode<AnyType> right;
	int height;		
}

这是AVL树的节点声明,声明了节点,左右子树以及高度。

在进行插入和删除操作时可能会使AVL树左右子树的高度相差超过1,破坏了平衡,当平衡破坏时,在插入或删除完成前恢复平衡要进行旋转。旋转分为单旋转和双旋转。把必须重新平衡的节点叫做t,下面是单旋转和双旋转的情况。

1.对于t的左儿子的左子树进行插入->单旋转

2.对于t的左儿子的右子树进行插入->双旋转

3.对于t的右儿子的左子树进行插入->双旋转

4.对于t的右儿子的右子树进行插入->单旋转

由此总结,左-左,右-右是单旋转,左-右,右-左是双旋转

在旋转之前,插一下节点高度计算

private int height(AVLNode<AnyType> t){
	return t == null ? -1 : t.height;
}

1.左-左:单旋,右旋


private AVLNode<AnyType> rotateRight(AVLNode<AnyType> k2){
	AVLNode<AnyType> k1 = k2.left;
	k2.left = k1.right;
	k2.height = Maht.max(height(k2.left),height(k2.right))+1;
	k1.height = Maht.max(height(k1.left),k2.height)+1;
	return k1;
}
2.左-右:双旋转,先左后右


private AVLNode<AnyType> doubleRight(AVLNode<AnyType> k3){
	k3.left = rotateLeft(k3.left);
	return rotateRight(k3);
}

3.右-左:双旋转,先右后左


private AVLNode<AnyType> doubleLeft(AVLNode<AnyType> k3){
	k3.right = rotateRightk3.right);
	return rotateLeft(k3);
}

4.右-右:单旋,左旋


private AVLNode<AnyType> rotateLeft(AVLNode<AnyType> k2){
	AVLNode<AnyType> k1 = k2.left;
	k2.left = k1.right;
	k2.height = Maht.max(height(k2.left),height(k2.right))+1;
	k1.height = Maht.max(height(k1.left),k2.height)+1;
	return k1;
}


说完了旋转,接下来就是插入操作了

private AVLNode<AnyType> insert(AnyType x,AVLNode<AnyType>t){
	if(t == null)
		return new AVLNode<>(x,null,null);
	int result = x.compareTo(t.element);
	if( result < 0)		//如果X小于节点值,则在左子树插入,递归更新
		t.left = insert(x,t.left);
	else if( result > 0)	//如果X大于节点值,则在右子树插入,递归
		t.right = insert(x,t.right);
	return balance(t);
}
private static final int balance_num = 1;
private AVLNode<AnyType> balance(AVLNode<AnyType>t){
	if(t == null)
		return t;
	if(height(t.left) - height(right) > balance_num){
		if(height(t.left.left) > height(t.left.right))  //左-左
			t = rotateRight(t);
		else
			t = doubleRight(t);	//左-右
	}else{
		if(height(t.right.right) > height(t.right.left))	//右-左
			t = rotateLeft(t);
		else
			t = doubleLeft(t);	//右-左
	}

	t.height = Math.max(height(t.left),height(t.right))+1;
	return t;
}

旋转一定要保持平衡,所以要返回的是balance(t)而不是t。


接下来进行删除操作,删除较插入更为复杂。

private AVLNode<AnyType> remove(AnyType x,AVLNode<AnyType>t){
	if(t == null)
		return new AVLNode<>(x,null,null);
	int result = x.compareTo(t.element);
	if( result < 0)		//如果X小于节点值,则在左子树删除,递归更新
		t.left = insert(x,t.left);
	else if( result > 0)	//如果X大于节点值,则在右子树删除,递归
		t.right = insert(x,t.right);
	else if(t.left != null && t.right != null){
		t.element = findMin(t.right).element;	//找到右子树最小值
		t.right = remove(t.element,t.right)		//删除右子树最小值原来的位置
	}
	else
		t = (t.left != null)?t.left:t.right;	//如果是一个儿子或者没有,哪个儿子不为空就返回哪个儿子
	return balance(t);
}

总体来说删除操作和二叉搜索树的想法包括代码都几乎是一致的,但是重要不同的一点就是AVL树需要进行旋转重平衡。理解了旋转就基本上插入删除思路想法和二叉搜索都一致。

最后说明部分图片是我搜的,如果侵权或者有问题,在此向您道歉,并删除照片。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值