AVL樹的實現

AVL樹:
AVL樹也成爲平衡二叉樹,它是這樣定義的:
一棵AVL樹或者是空樹,或者是具有以下性質的二叉搜索樹:
1、它的左右子樹都是AVL樹
2、左子樹和右子樹高度之差(簡稱平衡因子)的絕對值不超過1(-1、0、1)


AVL樹的插入:
在插入節點後會造成父節點的平衡因子發生改變,需要從下往上更新平衡因子,若某一節點的平衡因子的絕對值大於1,說明以這個結點爲根的樹已經不平衡,此時就要去通過旋轉來讓數重新達到平衡狀態。

旋轉規則:
左單旋:在較高右子樹的右側插入了結點
右單旋:在較高左子樹的左側插入了結點

先左後右:在較高左子樹的右側插入了結點
先右後左:在較高右子樹的左側插入了結點

對於較高子樹的理解:
較高子樹就是不平衡樹中的高度較大的子樹。

下面是通過右左旋轉達到平衡和通過左旋轉達到平衡的例子:

下面是通過左右旋轉達到平衡和通過右旋轉達到平衡的例子:

通過上面的例子我們可以得到以下結論:
當一棵樹不平衡時,如果這棵樹根節點和其平衡因子不爲0的結點的平衡因子符號相同則通過一次旋轉即可重新平衡,否則就需要兩次旋轉。
根爲2,子節點爲1,通過左旋轉即可平衡
根爲2,子節點爲-1,通過右左旋轉才能平衡
根爲-2,子節點爲1,通過左右旋轉才能平衡
根爲-2,子節點爲-1,通過右旋轉即可平衡

注意:在旋轉完成之後記得要把平衡因子修改爲適當的值,可以通過畫出圖片做以分析,得到規律


代碼:

#include<iostream>
#include<windows.h>

using namespace std;

template<typename K, typename V>
struct AVLTreeNode
{
    AVLTreeNode()
    {}
    AVLTreeNode(const K& _key, const V& _value = V())
        : key(_key)
        , value(_value)
        , bf(0)
        , pLeft(NULL)
        , pRight(NULL)
        , pParent(NULL)
    {}
    K key;
    V value;
    int bf;
    AVLTreeNode *pLeft;
    AVLTreeNode *pRight;
    AVLTreeNode *pParent;
};

template<typename K, typename V>
class AVLTree
{
    typedef AVLTreeNode<K, V> Node;
public:
    AVLTree()
        :pRoot(NULL)
    {}
    bool Inserter(const K& _key)
    {
        //
        Node* pCur = pRoot;
        Node* parent = NULL;
        if (NULL == pRoot)
        {
            pRoot = new Node(_key);
            return true;
        }
        else
        {
            //找到插入位置
            while (pCur)
            {
                if (pCur->key < _key)
                {
                    parent = pCur;
                    pCur = pCur->pRight;
                }
                else if (pCur->key > _key)
                {
                    parent = pCur;
                    pCur = pCur->pLeft;
                }
                else
                    return false;
            }
            //插入結點
            pCur = new Node(_key);
            if (parent->key > _key)
            {
                parent->pLeft = pCur;
            }
            else
                parent->pRight = pCur;
            pCur->pParent = parent;
        }
        //自下向上更新平衡因子
        while (parent)
        {
            //更新當前結點父節點的平衡因子
            if (parent->pLeft == pCur)
            {
                parent->bf--;
            }
            else
            {
                parent->bf++;
            }
            //如果其父節點的平衡因子爲0,則說明達到平衡
            if (0 == parent->bf)
            {
                break;
            }
            //如果是1,則繼續向上更新
            else if (1 == parent->bf || -1 == parent->bf)
            {
                pCur = parent;
                parent = pCur->pParent;
            }
            //不是1,就可能是+-2,此時子樹不平衡需要調整
            //一旦parent的因子絕對值==2,說明其需要調整,此時較高子樹是相對於它而言的
            else
            {
                //右子樹高
                if (parent->bf == 2)
                {

                    //右子樹的右側高
                    if (pCur->bf == 1)
                    {
                        //左旋轉
                        RotateLeft(parent);
                        break;
                    }
                    //右子樹的左側高
                    else
                    {
                        //右左旋轉
                        RotateRL(pCur);
                        break;
                    }
                }
                //左子樹高
                else
                {
                    //左子樹的左側高
                    if (pCur->bf == -1)
                    {
                        //右旋
                        RotateRight(parent);
                        break;
                    }
                    //左子樹的右側高
                    else
                    {
                        //左右旋轉
                        RotateLR(pCur);
                        break;
                    }
                }
            }
        }
        return true;
    }
    bool IsBalanceTree()//判斷樹是不是AVL樹
    {
        return _IsBalanceTree(pRoot);
    }
    int Hight()//求書的高度
    {
        return _Hight(pRoot);
    }
    void InOrder()
    {
        _InOrder(pRoot);
        cout << endl;
    }
private:
    bool _IsBalanceTree(Node *pRoot)
    {
        if (NULL == pRoot)
            return true;
        int left = _Hight(pRoot->pLeft);
        int right = _Hight(pRoot->pRight);

        if (pRoot->bf != (right - left) || std::abs(pRoot->bf) > 1)
            return false;
        return _IsBalanceTree(pRoot->pLeft) && _IsBalanceTree(pRoot->pRight);
    }
    void _InOrder(Node* pRoot)
    {
        if (NULL == pRoot)
            return;
        _InOrder(pRoot->pLeft);
        cout << pRoot->key << " ";
        _InOrder(pRoot->pRight);
    }
    int _Hight(Node* pRoot)
    {
        if (NULL == pRoot)
            return 0;
        if (NULL == pRoot->pLeft && NULL == pRoot->pRight)
            return 1;
        int left = _Hight(pRoot->pLeft)+1;
        int right = _Hight(pRoot->pRight)+1;
        return left > right ? left : right;
    }
    //左旋---->就是用父節點的右孩子去替換父節點,將父節點連接在其右孩子的左側
    void RotateLeft(Node *parent)
    {
        Node* pParent = parent->pParent;
        Node* pSubR = parent->pRight;
        Node* pSubRL = pSubR->pLeft;

        //父節點的右鏈接右孩子的左結點
        parent->pRight = pSubRL;
        //右孩子成爲父節點的父節點
        parent->pParent = pSubR;

        //右孩子的左結點存在,更新其父節點
        if (pSubRL)
            pSubRL->pParent = parent;
        //更新右孩子的父節點和左結點
        pSubR->pParent = pParent;
        pSubR->pLeft = parent;

        //如果pParent存在
        if (pParent)
        {
            //說明這是一顆子樹
            //將右節點連接在pParent的左或者右
            if (pParent->pLeft == parent)
            {
                pParent->pLeft = pSubR;
            }
            else
            {
                pParent->pRight = pSubR;
            }
        }
        //pParent不存在,說明父節點是樹根
        else//這是樹根將變爲右節點
            pRoot = pSubR;
        //將其平衡因子置0
        parent->bf = pSubR->bf = 0;
    }
    //右旋
    void RotateRight(Node* parent)
    {
        Node* pParent = parent->pParent;
        Node* pSubL = parent->pLeft;
        Node* pSubLR = pSubL->pRight;

        parent->pLeft = pSubLR;
        parent->pParent = pSubL;

        if (pSubLR)
            pSubLR->pParent = parent;

        pSubL->pParent = pParent;
        pSubL->pRight = parent;
        if (pParent)
        {
            if (pParent->pLeft == parent)
                pParent->pLeft = pSubL;
            else
                pParent->pRight = pSubL;
        }
        else
        {
            pRoot = pSubL;
        }
        parent->bf = pSubL->bf = 0;
    }
    //左右旋轉
    void RotateLR(Node* parent)
    {
        //判斷其右孩子的平衡因子
        int bf = parent->pRight->bf;
        //parent左旋,parent下降其父節點成爲其父節點的父節點
        RotateLeft(parent);
        //parent之前的父節點右旋
        RotateRight(parent->pParent->pParent);

        if (bf == -1)
        {//說明parent接受了其右孩子的左孩子,
            parent->pParent->pRight->bf = 1;
        }
        else if (1 == bf)
        {
            //說明parent的父節點,接受了其右孩子的右孩子
            parent->bf = -1;
        }
    }
    //右左旋轉
    void RotateRL(Node* parent)
    {
        int bf = parent->pLeft->bf;
        RotateRight(parent);
        RotateLeft(parent->pParent->pParent);
        if (1 == bf)
        {
            parent->pParent->pLeft->bf = -1;
        }
        else if (-1 == bf)
        {
            parent->bf = 1;
        }
    }
protected:
    Node* pRoot;
};




















































發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章