AVL树的实现

本文介绍了AVL树的基本概念,包括其定义、平衡条件及插入操作可能导致的不平衡情况。此外,还详细阐述了如何通过单旋转或多旋转恢复树的平衡状态,并提供了一个C++实现示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;
};




















































评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值