AVL 树,平衡二叉树,相比与二叉搜索树来说,多了一个平衡因子,该成员可以帮助二叉树进行自我平衡的调整
private:
Type data;
AVLNode *leftChild;
AVLNode *rightChild;
int bf;
那么,bf到底代表了什么含义呢,对每一个结点来说,它的平衡因子bf就是它的子树高度与右树高度差的绝对值,在二叉平衡树中,每插入一个新的结点,就要看一下它结点的平衡因子是否大于1,或者是否小于-1,当平衡因子的绝对值比1大时,就要进行平衡化调整。
而对于平衡化的调整,有以下几种情况(画术不精,望请见谅,以下四副图按顺序为1,2,3,4)
这四种情况就代表了要进行平衡化调整的四种情况
1.进行右旋转
2.先进行左旋转,在进行一次右旋转
3.进行一次左旋转
4.先进性一次右旋转在进行一次左旋转
下面我们对这四种情况的旋转分别进行简单描述:
(1)右旋转,在我的理解上就是,单进行一次旋转的情况,如图一图三,就是一条道走的太黑,所以我们要把它往它不愿意去的那边掰弯,让它平衡,均衡发展,它往左偏,就把它往右掰,它往右偏,就把它往左边掰,以图一为例,旋转时将该子树的根节点转下来,作为它左孩子的右子树,平衡因子随之做相应调整,左旋转同理
(2)双旋转,以图二为例,要先做一次左旋转,在做一次右旋转,偏的不正常,就像走了一半弯路的想要从弯路的中间折回去,这肯定是不对的,要先回到你原本的弯路上,在做相应调整,如图二,左旋转就对它下面的两个结点进行调整,且对调了身份,父为子,子为父,接下来就像是回到了图一,在进行一次右旋转就好了
以上都是在不考虑中间结点没有其他结点的情况下,如果中间结点存在其他子树,比如右转,就要将其他子树取下来连接在被旋转下来结点的左子树上,可能说的不是太清楚,直接上代码,四种情况的旋转在代码中有具体的体现。
AVLNode<Type>* RotateL(AVLNode<Type> *&ptr)
{
AVLNode<Type> *subL = ptr;
ptr = subL->rightChild;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
ptr->bf = subL->bf = 0;
return ptr;
}
AVLNode<Type>* RotateR(AVLNode<Type> *&ptr)
{
AVLNode<Type> *subR = ptr;
ptr = subR->leftChild;
subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;
ptr->bf = subR->bf = 0;
return ptr;
}
AVLNode<Type>* RotateLR(AVLNode<Type> *&ptr)
{
AVLNode<Type> *subR = ptr;
AVLNode<Type> *subL = ptr->leftChild;
ptr = subL->rightChild;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
//bf
if(ptr->bf <= 0)
subL->bf = 0;
else
subL->bf = -1;
subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;
//bf
if(ptr->bf >= 0)
subR->bf = 0;
else
subR->bf = 1;
ptr->bf = 0;
return ptr;
}
AVLNode<Type>* RotateRL(AVLNode<Type> *&ptr)
{
AVLNode<Type> *subL = ptr;
AVLNode<Type> *subR = ptr->rightChild;
ptr = subR->leftChild;
subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;
//bf
if(ptr->bf >= 0)
subR->bf = 0;
else
subR->bf = 1;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
//bf
if(ptr->bf <= 0)
subL->bf = 0;
else
subL->bf = -1;
ptr->bf = 0;
return ptr;
}
private:
AVLNode<Type> *root;
};