一颗AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树(空树的高度定位-1)。
二叉查找树的性质:对于树中的每个节点X,它的左子树中所有项的值小于X中的项,而它的右子树的所有项的值大于X中的项。
1.AVL树的插入
在树中插入一个值可能破坏AVL树的性质,所以我们要对树进行调整,这一操作就是旋转。
在插入以后,只有从插入点到根节点的的路径上的节点的平衡可能改变,因为只有这些节点的子树可能发生变化。假设a为必须重新平衡的节点,那么不平衡的情况是下面四种:
- 对a的左儿子的左子树进行一次插入
- 对a的左儿子的右子树进行一次插入
- 对a的右儿子的左子树进行一次插入
- 对a的右儿子的右子树进行一次插入
对于插入发生在外面的情况(即左-左和右-右),通过对树进行单旋转完成调整,而对于初入发生在内部的情况(即左-右和右-左),通过对树进行双旋转来完成调整
2.单旋转
节点k2不满足AVL的性质,其左子树比右子树深2层。为了使其平衡,我们要将X提上一层。调整的方法可以这样形容:将树想象成是柔软灵活的,抓住子节点k1,闭上你的双眼,使劲摇动它,在重力的作用下,k1变成了新的根。再者根据二叉查找树的性质,原来的树中k2>k1,于是在新树中k2变成k1的右儿子。子树Y包含原树中介于k1和k2之间的那些节点,那么它就放在了k2的左儿子的位置上。
3.双旋转
对于图示左边,用单旋转调整,对k1,k2之间进行旋转发现解决不了问题,我们只能将k2作为新的根。这使得k1成为k2的左子树,k3成为k2的右子树。
4.插入的基本思路
为将项是X的一个新节点 插入到一棵AVL树T中去,我们递归地结果X插入到T的相应的子树(称为Tlr)中,如果Tlr的高度不变,则插入完成,否则T中出现了高度不平衡,则根据情况进行单旋转或者双旋转的调整,更新高度(并且解决好与树的其余部分的链接)从而完成插入。
5.代码部分
- AVL树的申明
public class AVLnode {
AVLnode(int element)
{
this(element,null,null);
}
AVLnode(int element, AVLnode lt, AVLnode rt)
{
this.element = element;
left = lt;
right = rt;
}
int element;
AVLnode left;
AVLnode right;
int height;
}
单旋转(左-左)(对于右-右的情况是对称的)
private AVLnode rotateWithLeftChild(AVLnode k2)
{
AVLnode k1 = k2.left;
k2.left = k1.right;
k1.right = k2;
k2.height = Math.max(height(k2.left),height(k2.right))+1;
k1.height = Math.max(height(k1.left),height(k1.right))+1;
return k1;
}
- 双旋转(左-右)(右-左的情况是对称的)
private AVLnode doubleWithLeftChild(AVLnode k3)
{
k3.left = rotateWithRightChild(k3.left);
return rotateWithLeftChild(k3);
}
- 插入(总代码)
package AVL;
public class test {
//得到高度
private int height(AVLnode t)
{
return t==null?-1:t.height;
}
//插入
private AVLnode insert(int x, AVLnode t)
{
if( t== null)
return new AVLnode(x,null,null);
if(x<t.element)
{
t.left = insert(x,t.left);
if(height(t.left)-height(t.right)==2)
if(x<t.left.element)
t = rotateWithLeftChild(t);
else
t = doubleWithLeftChild(t);
}
else if(x>t.element)
{
t.right = insert(x,t.right);
if(height(t.right)-height(t.left)==2)
if(x>t.right.element)
t = rotateWithRightChild(t);
else
t = doubleWithRightChild(t);
}
t.height = Math.max(height(t.left),height(t.right))+1;
return t;
}
//左-左
private AVLnode rotateWithLeftChild(AVLnode k2)
{
AVLnode k1 = k2.left;
k2.left = k1.right;
k1.right = k2;
k2.height = Math.max(height(k2.left),height(k2.right))+1;
k1.height = Math.max(height(k1.left),height(k1.right))+1;
return k1;
}
//右右
private AVLnode rotateWithRightChild(AVLnode k2)
{
AVLnode k1 = k2.right;
k2.right = k1.left;
k1.left = k2;
k2.height = Math.max(height(k2.left),height(k2.right))+1;
k1.height = Math.max(height(k1.left),height(k1.right))+1;
return k1;
}
//左-右
private AVLnode doubleWithLeftChild(AVLnode k3)
{
k3.left = rotateWithRightChild(k3.left);
return rotateWithLeftChild(k3);
}
//右-左
private AVLnode doubleWithRightChild(AVLnode k3)
{
k3.right = rotateWithLeftChild(k3.right);
return rotateWithRightChild(k3);
}
}