一、AVL树的概念
AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为1,所以它也被称为高度平衡树。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。
二、AVL树相关算法
1.AVL树的结点定义
class AVLNode{
AVLNode leftchild;//左孩子
AVLNode rightchild;//右孩子
AVLNode parent;//双亲结点
int balance;//右孩子-左孩子
int key;
public AVLNode(){
key=0;
leftchild=rightchild=parent=null;
}
public AVLNode(int x){
key=x;
leftchild=rightchild=parent=null;
}
public AVLNode(int x, AVLNode left, AVLNode pa, AVLNode right){
key=x;
leftchild=left;
parent=pa;
rightchild=right;
}
}
2.AVL树左旋
如果在子树E中插入一个新结点,该子树高度增1导致结点A的平衡因子变成+2,出现不平衡。
为使树恢复平衡,从A沿插入路径连续取3个结点A、C和E。它们处于一条方向为“1”的直线上,需要做左单旋转。
以结点C为旋转轴,让结点A反时针旋转。
解题思路:
private void RotateLeft(AVLNode ptr){
AVLNode newroot=ptr.rightchild;//对应第一步
newroot.parent=ptr.parent;//1维护双亲
ptr.rightchild=newroot.leftchild;//对应第二步
//2维护双亲
if(newroot.leftchild!=null) {
newroot.leftchild.parent = ptr;
}
newroot.leftchild=ptr;//对应第三步
//新根
AVLNode pa=ptr.parent;
if(pa==null){
root=newroot;
}else {
if(pa.leftchild==ptr){
pa.leftchild=newroot;
}else {
pa.rightchild=newroot;
}
}
ptr.parent=newroot;//3维护双亲
}
主要完成三步代码后,对应为其添加维护双亲结点,以及根节点。
3.AVL树的右旋
在左子树D上插入新结点使其高度增1,导致结点A的平衡因子增到-2,造成了不平衡。
为使树恢复平衡,从A沿插入路径连续取3个结点A、B和D,它们处于一条方向为“/”的直线上,需要做右单旋转。
以结点B为旋转轴,将结点A顺时针旋转。
解题思路:
private void RotateRight(AVLNode ptr){
AVLNode newroot=ptr.leftchild;
newroot.parent=ptr.parent;
ptr.leftchild=newroot.rightchild;
if(newroot.rightchild!=null){
newroot.rightchild.parent=ptr;
}
newroot.parent=ptr;
AVLNode pa=ptr.parent;
if(pa==null){
root=newroot;
}else {
if(pa.leftchild==ptr){
pa.leftchild=newroot;
}else {
pa.rightchild=newroot;
}
ptr.parent=newroot;
}
}
4.AVL树的双旋
1)左单旋–》右单旋
在子树F或G中插入新结点,该子树的高度增1。结点A的平衡因子变为-2,发生了不平衡。
从结点A起沿插入路径选取3个结点A、B和E,它们位于一条形如“<”的折线上,因此需要进行先左后右的双旋转。
旋转思路:
private void LeftBalance(AVLNode ptr){
AVLNode leftsub=ptr.leftchild,rightsub=null;
switch (leftsub.balance){
case 0://平衡因子为0时说明是平衡的
System.out.println("left is balance \n"); break;
//平衡因子为-1时,说明处于的时一条斜线,因此进行右旋
case -1:
ptr.balance=0;
leftsub.balance=0;
RotateRight(ptr);
break;
//当平衡因子为1时,则说明是一条折线
case 1:
//指向这个不平衡的因子
rightsub=leftsub.rightchild;
//根据不同情况重置它们的平衡因子
switch (rightsub.balance){
case 1:
ptr.balance=0;
leftsub.balance=-1;
break;
case 0:
ptr.balance=0;
leftsub.balance=0;
break;
case -1:
ptr.balance=1;
leftsub.balance=0;
break;
}
rightsub.balance=0;
//进行左旋、右旋
RotateLeft(leftsub);
RotateRight(ptr);
break;
}
}
2)右单旋–》左单旋
此次双旋则是上一个双旋的镜像操作
private void RightBalance(AVLNode ptr){
AVLNode rightsub=ptr.rightchild,leftsub=null;
switch (rightsub.balance){
case 0:
System.out.println("right is balance \n"); break;
case 1:
ptr.balance=0;
rightsub.balance=0;
RotateLeft(ptr);
break;
case -1:
leftsub=rightsub.leftchild;
switch (leftsub.balance){
case 1:
ptr.balance=-1;
rightsub.balance=0;
break;
case 0:
ptr.balance=0;
leftsub.balance=0;
break;
case -1:
ptr.balance=0;
rightsub.balance=1;
break;
}
leftsub.balance=0;
RotateRight(rightsub);
RotateLeft(ptr);
break;
}
}