AVL树之插入与判断

二叉搜索树是为了降低遍历的时间复杂度,但是对于单支情况并不能很好的解决,要遍历一个左单支或右单支的二叉树,时间复杂度和链表相同,所以就引入了—>AVL树。
AVL树和一般的搜索二叉树相比有什么不同呢?
AVL树在搜索二叉树的基础上每个节点都加了一个平衡因子。
平衡因子的计算方法就是:右子树的深度 – 左子树的深度,或者也可以是,左子树的深度 – 右子树的深度。
当平衡因子的值 >= 2或<= -2时就需要调整了,而调整的方法就是:旋转。
旋转的方法分为四种:左单旋、右单旋、左右双旋和右左双旋。
左单旋:
对于pParent == 2,
pCur == 1
《AVL树之插入与判断》

void _RotateL(Node* pParent)
    {
        Node* pCur = pParent->_pRight;
        Node* pTmp = pCur->_pLeft;

        Node* pPParent = pParent->_pParent;
        pParent->_pRight = pTmp;
        if(pTmp)
            pTmp->_pParent = pParent;
        pCur->_pLeft = pParent;
        pParent->_pParent = pCur;
        if(pPParent ==NULL)
            _pRoot = pParent;
        else
        {
            if(pPParent->_pLeft == pParent)
                pPParent->_pLeft = pCur;
            else
                pPParent->_pRight = pCur;
        }
        pCur->_pParent = pPParent;
        //更新平衡因子
        pParent->_bf = _Height(pParent->_pRight) - _Height(pParent->_pLeft);
        pCur->_bf = _Height(pCur->_pRight) - _Height(pCur->_pLeft);
    }

右单旋:
pParent == -2, pCur == -1
《AVL树之插入与判断》

void _RotateR(Node* pParent)
    {
        Node* pCur = pParent->_pLeft;
        Node* pTmp = pCur->_pRight;
        Node* pPParent = pParent->_pParent;

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

左右双旋:
pParent == -2, pCur == 1
《AVL树之插入与判断》
左右双旋只需调用左单旋和右单旋即可。

void _RotateLR(Node* pParent)
    {
        _RotateL(pParent->_pLeft);
        _RotateR(pParent);
    }

右左双旋:
pParent == 2, pCur==-1
《AVL树之插入与判断》

void _RotateRL(Node* pParent)
    {
        _RotateR(pParent->_pRight);
        _RotateL(pParent);
    }

整体插入代码:

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

    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(pCur->_key > key)
            {
                pParent = pCur;
                pCur = pCur->_pLeft;
            }
            else if(pCur->_key < key)
            {
                pParent = pCur;
                pCur = pCur->_pRight;
            }
            else
                return false;
        }
            pCur = new Node(key, value);
            //连接pParent与pCur
            if(pParent->_key > key)
                pParent->_pLeft = pCur;
            else
                pParent->_pRight = pCur;
            pCur->_pParent = pParent;
            //调整
            while(pParent)
            {
                //先调整双亲的平衡因子
                if(pCur == pParent->_pLeft)
                    pParent->_bf --;
                else
                    pParent->_bf ++;
                if(pParent->_bf == 0)
                    return true;
                //如果双亲的平衡因子是1或-1,说明该子树增加了一层,需要向上调整平衡因子
                else if(abs(pParent->_bf) <= 1)
                {
                    pCur = pParent;
                    pParent = pParent->_pParent;
                }
                //此时的平衡因子是2或-2,需要进行旋转减小平衡因子
                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;
                }
        }
    }

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

    size_t Height()
    {
        return _Height(_pRoot);
    }

    bool IsBalanceTree()
    {
        return _IsBalanceTree(_pRoot);
    }
private:
    size_t _Height(Node* pRoot)
    {
        if(pRoot)
        {
            int HeightLeft = 0;
            int HeightRight = 0;
            if(pRoot->_pLeft)
                HeightLeft = _Height(pRoot->_pLeft);
            if(pRoot->_pRight)
                HeightRight = _Height(pRoot->_pRight);
            return HeightLeft>HeightRight ? HeightLeft+1 : HeightRight+1;
        }
        return 0;
    }

    void _InOrder(Node* pRoot)
    {
        if(pRoot)
        {
            _InOrder(pRoot->_pLeft);
            cout<<pRoot->_key<<" ";
            _InOrder(pRoot->_pRight);
        }
    }
private:
    Node* _pRoot;
};

如何判断一个AVL树是否平衡?
用递归的方法先遍历根节点,再遍历左子树,最后遍历右子树。判断根节点时应先判断平衡因子是否正确,再判断平衡因子的绝对值有没有大于1。

bool _IsBalanceTree(Node* pRoot)
    {
        if(pRoot == NULL)
            return true;
        if(pRoot->_bf != _Height(pRoot->_pRight) - _Height(pRoot->_pLeft) ||\
            abs(pRoot->_bf) >= 2)
            return false;
        if(pRoot->_pLeft)
            _IsBalanceTree(pRoot->_pLeft);
        if(pRoot->_pRight)
            _IsBalanceTree(pRoot->_pRight);

        return true;
    }
    原文作者:AVL树
    原文地址: https://blog.csdn.net/dong18292000671/article/details/72793097
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞