AVL树
一棵AVL树或者是空树,或者是具有下列性质的二叉搜索树:
- 它的左子树和右子树都是AVL树,
- 且左子树和右子树的高度之差的绝对值不超过1。
结点的平衡因子 balance(balance factor)
- 每个结点附加一个数字,给出该结点右子树的高度减去左子树的高度所得的高度差。这个数字即为结点的平衡因子 balance。
- 根据AVL树的定义,任一结点的平衡因子只能取 -1、0、1。
- 如果一个结点的平衡因子的绝对值大于1,则这棵二叉搜索树就失去了平衡,不再是AVL树。
- 如果一棵二叉搜索树是高度平衡的,它就成为AVL树。如果它有 n 个结点,其高度可保持在 O(log2n),平均搜索长度也可保持在 O(log2n)。
AVL树结构设计
class AVLNode{
private AVLNode leftChild;
private AVLNode parent;
private AVLNode rightChild;
private int data;
private int balance;
public AVLNode(){
leftChild = null;
parent = null;
rightChild = null;
data = 0;
}
public AVLNode(int data){
leftChild = null;
parent = null;
rightChild = null;
this.data = data;
}
public AVLNode(int data,AVLNode parent){
leftChild = null;
this.parent = parent;
rightChild = null;
this.data = data;
}
public AVLNode(int data,AVLNode parent,AVLNode leftChild,AVLNode rightChild){
this.leftChild = leftChild;
this.parent = parent;
this.rightChild = rightChild;
this.data = data;
}
}
private AVLNode head; //指向根节点
private int curSize; //记录有效个数
public AVLTree(){
curSize = 0;
head = new AVLNode();
}
平衡化旋转
- 如果在一棵平衡的二叉搜索树中插入了一个新结点,造成了不平衡。此时必须调整树的结构,使之平衡化。
- 平衡化旋转有两类:
- 单旋转(左单旋和右单旋)
- 双旋转(左平衡和右平衡)
- 每插入一个新结点时,AVL树中相关结点的平衡状态会发生改变。因此,在插入一个新的结点后,需要从插入位置沿通向根结点的路径进行回溯,检查各结点的平衡因子(左、右子树的高度差)。
- 如果在某一结点发现高度不平衡,停止回溯。
- 从发生不平衡的结点起,沿刚才回溯的路径取直接下两层的结点。
- 如果这三个结点处于一条直线上,则采用单旋转进行平衡化。单旋转可按其方向分为左单旋转和右单旋转,其中一个是另一个的镜像,其方向与不平衡的形状相关。
- 如果这三个结点处于一条折线上,则采用双旋转进行平衡化。双旋转分为先左后右和先右后左两类。
左单旋转(RotateLeft)
- 如果在子树E中插入一个新结点,该子树的高度增1导致结点A的平衡因子变成+2,出现不平衡。
- 为使树恢复平衡,从A沿插入路径连续取3个结点A、C和E。它们处于一条方向为“\”的直线上,需要做左单旋转。
- 以结点C为旋转轴,让结点A反时针旋转。
示例:
/**
* 左单旋转
* @param ptr
*/
private void RotateLeft(AVLNode ptr){
AVLNode newRoot = p