作为二叉查找树的升级版,平衡二叉树(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;
}以上是平衡二叉树的插入和删除部分代码,经过初步测试暂时没有问题,如果有问题,也希望大家多多指出,多多交流。
本文详细介绍了平衡二叉树(AVL-Tree)的概念及其在执行插入和删除操作后如何进行平衡操作,确保操作后的数仍然满足平衡二叉树的条件。通过具体的代码示例,展示了平衡二叉树在执行各种操作后的平衡调整过程,包括左单旋、左双旋、右单旋和右双旋四种常见情况。
406

被折叠的 条评论
为什么被折叠?



