1. 程式人生 > >C++模板實現二叉樹(六 AVL樹基礎與旋轉)

C++模板實現二叉樹(六 AVL樹基礎與旋轉)

dsw演算法可以從全域性平衡樹,但是,往往在插入於刪除動作發生時,將隻影響樹的一部分,此時重新平衡可以只在樹的一部分進行.AVL樹要求每個節點左右子樹的高度差最大為1.平衡因子用右子樹的高度減去左子樹的高度.在AVL樹中,平衡因子應該只有-1,0,1三種選擇.只要AVL樹中任意一個節點的平衡因子小於-1或者大於1,樹就要失去平衡.
以下4種情況會導致失去平衡:

  1. 當前節點平衡因子為-1,左子節點的平衡因子為0,在左子節點的左子樹中插入節點,導致當前節點的平衡因子變為-2(左子節點-1).通過右旋轉使其恢復平衡.
    這裡寫圖片描述
  2. 當前節點平衡因子為1,右子節點的平衡因子為0,在右子節點的右子樹中插入節點,導致當前節點的平衡因子變為2(右子節點1).使用左旋轉使其恢復平衡.
    這裡寫圖片描述
  3. 當前節點平衡因子為-1,左子節點的平衡因子為0,在左子節點的右子樹中插入節點,導致當前節點的平衡因子變為-2(左子節點1).使用先左後右旋轉使其恢復平衡.
    這裡寫圖片描述
  4. 當前節點平衡因子為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;
}