二叉樹搜索樹---AVL樹插入節點

1.AVL樹的概念:
AVL樹或則是空樹,或是具有下列性質的二叉搜索樹

  • 它的左右子樹都是AVL樹;
  • 左子樹和右子樹的高度之差簡稱(平衡因子)的絕對值不超過1;

2.AVL樹的實現原理
與二叉搜索樹的節點插入方法相同,具體步驟如下:
這裏寫圖片描述

當樹不平衡時,我們需要做出旋轉調整,有四種調整方法,分別爲右單旋、左單旋、先左單旋再右單旋、先右單旋在左單旋

  • 左單旋
    這裏寫圖片描述

  • 右單旋
    這裏寫圖片描述

  • 先右旋再左旋
    這裏寫圖片描述

  • 先左旋再右旋
    這裏寫圖片描述

3.代碼實現

#include<stdio.h>
#include<iostream>
using namespace std;

template<class k,class v>
struct AVLTreeNode
{
    AVLTreeNode(const k& key,const v& value)
        :_key(key)
        ,_value(value)
        ,_bf(0)
        ,_pLeft(NULL)
        ,_pRight(NULL)
        ,_pParent(NULL)
    {}

    AVLTreeNode<k,v>* _pLeft;
    AVLTreeNode<k,v>* _pRight;
    AVLTreeNode<k,v>* _pParent;
    k _key;
    v _value;
    int _bf;
};


template<class k,class v>
class AVLTree
{
public:
    typedef AVLTreeNode<k,v> Node;
    AVLTree()
        :_pRoot(NULL)
    {}

    bool Insert(const k& key,const v& value)//插入節點
    {
        return _Insert(key,value);
    }

    bool IsBalanceTree()
    {
        return _IsBalanceTree(_pRoot);
    }
private:
    bool _IsBalanceTree(Node* pRoot)//判斷該樹是否是平衡二叉樹
    {
        if(pRoot == NULL)
            return true;
        size_t leftHeight = _Height(pRoot->_pLeft);
        size_t rightHeight = _Height(pRoot->_pRight);

        if(rightHeight-leftHeight != pRoot->_bf || abs(pRoot->_bf)>1)
        {
            cout<<pRoot->_key<<"-->"<<pRoot->_bf<<endl;
            return false;
        }
        return _IsBalanceTree(pRoot->_pLeft)&&_IsBalanceTree(pRoot->_pRight);
    }
    size_t _Height(Node* pRoot)
    {
        if(pRoot == NULL)
            return 0;
        if(pRoot->_pLeft == NULL && pRoot->_pRight == NULL)
            return 1;

        size_t leftHeight = _Height(pRoot->_pLeft);
        size_t rightHeight = _Height(pRoot->_pRight);

        return 1+(leftHeight > rightHeight? leftHeight:rightHeight);
    }
    bool _Insert(const k& key,const v& value)
    {
        if(_pRoot == NULL)
        {
            _pRoot = new Node(key,value);
            return true;
        }

        //找到要插入節點的位置
        Node* pCur = _pRoot;
        Node* pParent = NULL;

        while(pCur)
        {
            if(key < pCur->_key)
            {
                pParent = pCur;
                pCur = pCur->_pLeft;
            }
            else if(key > pCur->_key)
            {
                pParent = pCur;
                pCur = pCur->_pRight;
            }
            else
                return false;
        }
        //已經找到插入位置
        pCur = new Node(key,value);
        if(pParent->_key < key)
        {
            pParent->_pRight = pCur;
            pCur->_pParent = pParent;
        }
        else
        {
            pParent->_pLeft = pCur;
            pCur->_pParent = pParent;
        }


        while(pParent)
        {
            //更新平衡因子
            if(pParent->_pLeft == pCur)
                (pParent->_bf)--;
            else
                (pParent->_bf)++;

            if(pParent->_bf == 0)//pParent只有左孩子或者只有右孩子,在其空指針域插入一個節點後,平衡因子爲0,
                return true;     //此時樹的高度沒有發生變化,該樹任然是是AVL樹
            else if(pParent->_bf == -1 || pParent->_bf == 1)//pParent是葉子節點,插入節點後其平衡因子可能是1或-1
            {                                             //此時樹的高度可能發生了改變,我們要向上判斷其祖先節點是否平衡
                pCur = pParent;
                pParent = pCur->_pParent;
            }
            else
            {
                //不滿足平衡樹,要做旋轉處理
                if(pParent->_bf == 2)//右子樹
                {
                    if(pCur->_bf == 1)//右側
                        _RotateL(pParent);//左旋調整
                    else//左側
                        _RotateRL(pParent);//先右旋再左旋
                }
                else//左子樹
                {
                    if(pCur->_bf == -1)//左側
                        _RotateR(pParent);
                    else//右側
                        _RotateLR(pParent);
                }
                break;//調整完後跳出循環
            }
        }
        return true;
    }

    void InOrder()
    {
        cout<<"InOrder ";
        _InOrder(_pRoot);
        cout<<endl;
    }

private:
    void _InOrder(Node*& pRoot)
    {
        if(pRoot)
        {
            _InOrder(pRoot->_pLeft);
            cout<<pRoot->_key<<" ";
            _InOrder(pRoot->_pRight);
        }
    }
    void _RotateL(Node* pParent)
    {
        Node* pSubR = pParent->_pRight;
        Node* pSubRL =pSubR->_pLeft;

        pParent->_pRight = pSubRL;
        if(pSubRL)//情況四之一
            pSubRL->_pParent = pParent;

        pSubR->_pLeft = pParent;

        Node* pPParent = pParent->_pParent;
        pParent->_pParent = pSubR;
        if(pPParent == NULL)
        {
            _pRoot = pSubR;
            pSubR->_pParent = NULL;
        }
        else if(pPParent->_pLeft == pParent)
        {
            pPParent->_pLeft = pSubR;
            pSubR->_pParent = pPParent;
        }
        else
        {
            pPParent->_pRight = pSubR;
            pSubR->_pParent = pPParent;
        }

        //更新平衡因子
        pParent->_bf = pSubR->_bf = 0;
    }

    void _RotateR(Node* pParent)
    {
        Node* pSubL = pParent->_pLeft;
        Node* pSubLR = pParent->_pRight;

        pParent->_pLeft = pSubLR;
        if(pSubLR)
            pSubLR->_pParent = pParent;
        pSubL->_pRight = pParent;

        Node* pPParent = pParent->_pParent;
        pParent->_pParent = pSubL;

        if(pPParent == NULL)
        {
            _pRoot = pSubL;
            pSubL->_pParent = NULL;
        }
        else if(pPParent->_pLeft == pParent)
        {
            pPParent->_pLeft = pSubL;
            pSubL->_pParent = pPParent;
        }
        else
        {
            pPParent->_pRight = pSubL;
            pSubL->_pParent = pPParent;
        }
        //更新平衡因子
        pParent->_bf = pSubL->_bf = 0;
    }

    void _RotateRL(Node* pParent)//先右單旋再左單旋
    {
        Node* pSubR = pParent->_pRight;
        Node* pSubRL = pSubR->_pLeft;
        int bf = pSubRL->_bf;

        _RotateR(pParent->_pRight);
        _RotateL(pParent);

        //判斷平衡因子應該如何更新
        if(bf == 1)
            pParent->_bf = -1;
        else
            pSubR->_bf = 1;
    }

    void _RotateLR(Node* pParent)//先左單旋再右單旋
    {
        Node* pSubL = pParent->_pLeft;
        Node* pSubLR = pSubL->_pRight;
        int bf = pSubLR->_bf;

        _RotateL(pParent->_pLeft);
        _RotateR(pParent);

        //判斷平衡因子應該如何修改
        if(bf == 1)
            pSubL->_bf = -1;
        else
            pParent->_bf = 1;
    }

private:
    Node* _pRoot;
};

測試代碼:

void funtest()
{
    int array[] = {2,1,4,3,5,6};//測試左單旋
    AVLTree<int,int> bst;
    for(size_t idx= 0 ;idx < sizeof(array)/sizeof(array[0]);++idx)
        bst.Insert(array[idx],idx);

    AVLTree<int,int> bst1;
    int array1[] = {5,3,6,2,1,4};//測試右單旋
    for(size_t idx1= 0 ;idx1 < sizeof(array1)/sizeof(array1[0]);++idx1)
        bst1.Insert(array1[idx1],idx1);
}

void funtest1()
{
    int array[] = {3,2,1,4,5,6,7,10,9,8};//測試左單旋
    AVLTree<int,int> bst;
    for(size_t idx= 0 ;idx < sizeof(array)/sizeof(array[0]);++idx)
        bst.Insert(array[idx],idx);
    if(bst.IsBalanceTree())
    {
        cout<<"IS AVLTree"<<endl;
    }
    else
    {
        cout<<"NO IS AVLTree"<<endl;
    }
}

int main()
{
    //funtest();
    funtest1();
    getchar();
    return 0;
}
發佈了109 篇原創文章 · 獲贊 17 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章