dsw算法可以从全局平衡树,但是,往往在插入于删除动作发生时,将只影响树的一部分,此时重新平衡可以只在树的一部分进行.AVL树要求每个节点左右子树的高度差最大为1.平衡因子用右子树的高度减去左子树的高度.在AVL树中,平衡因子应该只有-1,0,1三种选择.只要AVL树中任意一个节点的平衡因子小于-1或者大于1,树就要失去平衡.
以下4种情况会导致失去平衡:
- 当前节点平衡因子为-1,左子节点的平衡因子为0,在左子节点的左子树中插入节点,导致当前节点的平衡因子变为-2(左子节点-1).通过右旋转使其恢复平衡.
- 当前节点平衡因子为1,右子节点的平衡因子为0,在右子节点的右子树中插入节点,导致当前节点的平衡因子变为2(右子节点1).使用左旋转使其恢复平衡.
- 当前节点平衡因子为-1,左子节点的平衡因子为0,在左子节点的右子树中插入节点,导致当前节点的平衡因子变为-2(左子节点1).使用先左后右旋转使其恢复平衡.
- 当前节点平衡因子为1,右子节点的平衡因子为0,在右子节点的左子树中插入节点,导致当前节点的平衡因子变为2(右子节点-1).使用先右后左旋转使其恢复平衡.(与3对称)
核心代码分析:
在插入节点后,首先更新平衡因子,从插入节点往上依次更新.
碰到更新为-2或2时,即中止,准备开始进行旋转.
如果碰到更新为0时,则中止,不需要旋转.
数据结构上,AVLNode比BinNode需要增加平衡因子和指向父亲的指针。
AVLNode的数据结构:
template <class T>
class AVLNode : public BinNode<T>
{
public:
AVLNode();
AVLNode(const T& data, AVLNode<T> *l = NULL, AVLNode<T> *r = NULL, AVLNode<T> *p = NULL);
AVLNode<T>* pa;
int balanceValue;
AVLNode<T>* left;
AVLNode<T>* right;
};
对应旋转的代码如下:
template <class T, unsigned int capacity>
void BinSearchTreeAVL<T, capacity>::updateBalanceFactors(AVLNode<T>* avlNode)
{
if (root == avlNode)
{
root->balanceValue = 0;
}
else
{
AVLNode<T> *pa = avlNode->pa;
if (pa->left == avlNode)
{
pa->balanceValue--;
}
else
{
pa->balanceValue++;
}
while ((root != pa) && (pa->balanceValue != 2) && (pa->balanceValue != -2))
{
AVLNode<T> *curr = pa;
pa = pa->pa;
if (curr->balanceValue == 0)
{
return; //no need to balance
}
else if (curr == pa->left)
{
pa->balanceValue--;
}
else
{
pa->balanceValue++;
}
}
if ((pa->balanceValue == 2) || (pa->balanceValue == -2))
{
//rotation to AVL balance
//the new insert node in right tree right
if ((pa->balanceValue == 2) && (NULL != pa->right) && (/*static_cast<AVLNode<T>*>*/(pa->right)->balanceValue == 1))
{
//update balance value of pa and ch, then rotation left, last update fa pointer
pa->balanceValue = 0;
/*static_cast<AVLNode<T>*>*/(pa->right)->balanceValue = 0;
AVLNode<T>* grNode = pa->pa;
AVLNode<T>* paNode = pa;
AVLNode<T>* chNode = /*static_cast<AVLNode<T>*>*/(pa->right);
AVLNode<T>* chLNode = chNode->left;
rotationLeft(grNode, paNode, chNode);
paNode->pa = chNode;
chNode->pa = grNode;
if (NULL != chLNode)
{
chLNode->pa = paNode;
}
}
//the new insert node in right tree left
else if ((pa->balanceValue == 2) && (NULL != pa->right) && (/*static_cast<AVLNode<T>*>*/(pa->right)->balanceValue == -1))
{
AVLNode<T>* rotationRGrNode = pa;
AVLNode<T>* rotationRPaNode = /*static_cast<AVLNode<T>*>*/(pa->right);
AVLNode<T>* rotationRChNode = /*static_cast<AVLNode<T>*>*/(pa->right->left);
int rotationRChNodeBalanceValue = rotationRChNode->balanceValue;
AVLNode<T>* rotationRChRChNode = /*static_cast<AVLNode<T>*>*/(pa->right->left->right);
rotationRight(rotationRGrNode, rotationRPaNode, rotationRChNode);
rotationRChNode->pa = rotationRGrNode;
rotationRPaNode->pa = rotationRChNode;
if (NULL != rotationRChRChNode)
{
rotationRChRChNode->pa = rotationRPaNode;
}
AVLNode<T>* rotationLGrNode = rotationRGrNode->pa;
AVLNode<T>* rotationLPaNode = rotationRGrNode;
AVLNode<T>* rotationLChNode = rotationRChNode;
AVLNode<T>* rotationLChLChNode = /*static_cast<AVLNode<T>*>*/(rotationLChNode->left);
rotationLeft(rotationLGrNode, rotationLPaNode, rotationLChNode);
rotationLChNode->pa = rotationLGrNode;
rotationLPaNode->pa = rotationLChNode;
if (NULL != rotationLChLChNode)
{
rotationLChLChNode->pa = rotationLPaNode;
}
if (1 == rotationRChNodeBalanceValue)
{
rotationRGrNode->balanceValue = -1;
rotationRPaNode->balanceValue = 0;
rotationRChNode->balanceValue = 0;
}
else if (-1 == rotationRChNodeBalanceValue)
{
rotationRGrNode->balanceValue = 0;
rotationRPaNode->balanceValue = 1;
rotationRChNode->balanceValue = 0;
}
else
{
rotationRGrNode->balanceValue = 0;
rotationRPaNode->balanceValue = 0;
rotationRChNode->balanceValue = 0;
}
}
//the new insert node in left tree left
else if ((pa->balanceValue == -2) && (NULL != pa->left) && (/*static_cast<AVLNode<T>*>*/(pa->left)->balanceValue == -1))
{
//update balance value of pa and ch, then rotation right, last update fa pointer
/*static_cast<AVLNode<T>*>*/(pa->left)->balanceValue = 0;
pa->balanceValue = 0;
AVLNode<T>* grNode = pa->pa;
AVLNode<T>* paNode = pa;
AVLNode<T>* chNode = /*static_cast<AVLNode<T>*>*/(pa->left);
AVLNode<T>* chRNode = chNode->right;
rotationRight(grNode, paNode, chNode);
paNode->pa = chNode;
chNode->pa = grNode;
if (NULL != chRNode)
{
chRNode->pa = paNode;
}
}
//the new insert node in left tree right
else if ((pa->balanceValue == -2) && (NULL != pa->left) && (pa->left->balanceValue == 1))
{
AVLNode<T>* rotationLGrNode = pa;
AVLNode<T>* rotationLPaNode = /*static_cast<AVLNode<T>*>*/(pa->left);
AVLNode<T>* rotationLChNode = /*static_cast<AVLNode<T>*>*/(pa->left->right);
int rotationLChNodeBalanceValue = rotationLChNode->balanceValue;
AVLNode<T>* rotationLChLChNode = /*static_cast<AVLNode<T>*>*/(pa->left->right->left);
rotationLeft(rotationLGrNode, rotationLPaNode, rotationLChNode);
rotationLChNode->pa = rotationLGrNode;
rotationLPaNode->pa = rotationLChNode;
if (NULL != rotationLChLChNode)
{
rotationLChLChNode->pa = rotationLPaNode;
}
AVLNode<T>* rotationRGrNode = rotationLGrNode->pa;
AVLNode<T>* rotationRPaNode = rotationLGrNode;
AVLNode<T>* rotationRChNode = rotationLChNode;
AVLNode<T>* rotationRChRChNode = /*static_cast<AVLNode<T>*>*/(rotationRChNode->right);
rotationRight(rotationRGrNode, rotationRPaNode, rotationRChNode);
rotationRChNode->pa = rotationRGrNode;
rotationRPaNode->pa = rotationRChNode;
if (NULL != rotationRChRChNode)
{
rotationRChRChNode->pa = rotationRPaNode;
}
if (1 == rotationLChNodeBalanceValue)
{
rotationLGrNode->balanceValue = 0;
rotationLPaNode->balanceValue = -1;
rotationLChNode->balanceValue = 0;
}
else if (-1 == rotationLChNodeBalanceValue)
{
rotationLGrNode->balanceValue = 1;
rotationLPaNode->balanceValue = 0;
rotationLChNode->balanceValue = 0;
}
else
{
rotationLGrNode->balanceValue = 0;
rotationLPaNode->balanceValue = 0;
rotationLChNode->balanceValue = 0;
}
}
else
{
//should be error case
}
}
}
return;
}