C++模板實現二叉樹(六 AVL樹基礎與旋轉)
阿新 • • 發佈:2019-01-30
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;
}