C++AVL树

目录

一、平衡搜索二叉树实现方式:

二、AVL树的插入

三、AVL树的中序遍历、判断、高度以及大小计算


一、平衡搜索二叉树实现方式:

        这里采用平衡因子的方式记录左右子树高度,并在普通搜索二叉树的基础上再每个节点中加上一个指向父节点的指针以方便链接

        代码如下:

template <class K, class V>
struct AVLTreeNode
{
	pair<K, V> _kv;
	AVLTreeNode* _left;
	AVLTreeNode* _right;
	AVLTreeNode* _parent;
	int _bf;
	AVLTreeNode(const pair<K, V>& kv)
		: _kv(kv)
		, _left(nullptr)
		, _right(nullptr)
		, _parent(nullptr)
		, _bf(0)
	{

	}
};

二、AVL树的插入

        这是最难的地方,但可以分为一下三步进行:

        1、找到可以进行插入的叶子结点,或者是只有一个子节点的节点

        2、进行插入,将新节点与找到的父节点之间进行链接

        3、更新平衡因子,并判断是否需要进行旋转,二者有分为四种情况:左单旋(插入在最右边)、右单旋(插入在最左边)、左右单旋(插入在左子树的右边)、右左单旋(插入在右子树的左边)

        首先是插入的核心代码(为了防止逻辑失误,所以这里在所有的if、else if之外还加上了应有情况的以外情况,一旦出现立即报错)

template<class K, class V>
class AVLTree
{
	typedef AVLTreeNode<K, V> Node;
public:
    bool Insert(const pair<K, V>& kv)
    {
        if (_root == nullptr)
        {
            _root = new Node(kv);
            return true;
        }
        //先找到要用于插入的叶子结点或者是只有一个孩子的父节点
        Node* parent = nullptr;
        Node* cur = _root;
        while (cur)
        {
            if (cur->_kv.first < kv.first)
            {
                parent = cur;
                cur = cur->_right;
            }
            else if (cur->_kv.first > kv.first)
            {
                parent = cur;
                cur = cur->_left;
            }
            else
            {
                return false;
            }
        }
        //链接新的叶子结点
        cur = new Node(kv);
        if (parent->_kv.first < kv.first)
        {
            parent->_right = cur;
        }
        else
        {
            parent->_left = cur;
        }
        //链接叶子结点的父节点
        cur->_parent = parent;
        //控制平衡
        //更新平衡因子
        // 1.平衡因子等于右子树高度-左子树高度
        // 2、只有子树高度变化才会影响当前节点的平衡因子
        // 3、插入节点在父亲的左子树,平衡因子--;插入节点在父亲的右子树,平衡因子++
        // 4、parent所在的子树的高度是否变化取决于parent所在的子树的高度是否变化
        // 
        // 更新停止条件:
        // 1、更新后parent的平衡因子是0,说明由-1到了0,或者由1到了0,说明插在了矮的那一边
        // 因此高度不变,停止更新
        // 2、更新后parent的平衡因子是1或-1,说明原来一样高,这样高度变了,继续更新
        // 3、更新后parent的平衡因子是2或-2,说明插在了高的一边,继续更新需要旋转
        while (parent)
        {
            if (cur == parent->_left)
            {
                parent->_bf--;
            }
            else
            {
                parent->_bf++;
            }

            //插入以后高度差为0
            if (parent->_bf == 0)
            {
                break;
            }
            //继续更新,对上层的因子也造成了影响,因为原本高度差为零 
            else if (parent->_bf == 1 || parent->_bf == -1)
            {
                cur = parent;
                parent = parent->_parent;
            }
            //插在了原本就高的子树
            else if (parent->_bf == 2 || parent->_bf == -2)
            {
                //旋转的原则:
                // 要做到的三个点:
                // 1、保持搜索树规则
                // 2、变平衡
                // 3、降低树的高度 
                //
                if (parent->_bf == -2 && cur->_bf == -1)
                {
                    RotateR(parent);
                }
                else if (parent->_bf == 2 && cur->_bf == 1)
                {
                    RotateL(parent);
                }
                else if (parent->_bf == -2 && cur->_bf == 1)
                {
                    RotateLR(parent);
                }
                else if(parent->_bf == 2 && cur->_bf == -1)
                {
                    RotateRL(parent);
                }
                else
                {
                    assert(false);
                }
                break;
            }
            else
            {
                assert(false);
            }
        }

        return true;
    }

        接下来是四种旋转的代码(前两种旋转完全类似,后两种旋转也是完全类似)

        

 void RotateR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;

        if (subLR != nullptr)
        {
            subLR->_parent = parent;
        }
        Node* pParent = parent->_parent;
        subL->_right = parent;
        parent->_parent = subL;
        parent->_left = subLR;

        //有可能最新的parent是根节点
        if (parent == _root)
        {
            _root = subL;
            subL->_parent = nullptr;
        }
        //有可能旋转的是一颗子树
        else
        {
            if (pParent->_left == parent)
            {
                pParent->_left = subL;
            }
            else
            {
                pParent->_right = subL;
            }
            subL->_parent = pParent;
        }
        //这里不需要再继续更新,因为插入以前这里的pParent的_bf是零,插入并旋转以后,
        // 以subL为根子树的高度不发生改变
        subL->_bf = 0;
        parent->_bf = 0;
    }

    void RotateL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;

        if (subRL != nullptr)
        {
            subRL->_parent = parent;
        }
        parent->_right = subRL;
        Node* pParent = parent->_parent;
        parent->_parent = subR;
        subR->_left = parent;

        if (parent == _root)
        {
            _root = subR;
            subR->_parent = nullptr;
        }
        else
        {
            if (pParent->_left == parent)
            {
                pParent->_left = subR;
            }
            else
            {
                pParent->_right = subR;
            }
            subR->_parent = pParent;
        }

        subR->_bf = 0;
        parent->_bf = 0;
    }

    void RotateLR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        int bf = subLR->_bf;
        //旋转
        RotateL(parent->_left);
        RotateR(parent);
        //更新平衡因子
        if (bf == -1)
        {
            subLR->_bf = 0;
            subL->_bf = 0;
            parent->_bf = 1;
        }
        else if (bf == 1)
        {
            subLR->_bf = 0;
            subL->_bf = -1;
            parent->_bf = 0;
        }
        else if(bf == 0)
        {
            subLR->_bf = 0;
            subL->_bf = 0;
            parent->_bf = 0;
        }
        else
        {
            assert(false);
        }
    }

    void RotateRL(Node* parent)
    {
        Node* subR = parent->_right;
        Node* subRL = subR->_left;
        int bf = subRL->_bf;
        RotateR(parent->_right);
        RotateL(parent);

        if (bf == 1)
        {
            subR->_bf = 0;
            subRL->_bf = 0;
            parent->_bf = -1;
        }
        else if (bf == -1)
        {
            subR->_bf = 1;
            subRL->_bf = 0;
            parent->_bf = 0;
        }
        else if (bf == 0)
        {
            subR->_bf = 0;
            subRL->_bf = 0;
            parent->_bf = 0;
        }
        else
        {
            assert(false);
        }
    }

三、AVL树的中序遍历、判断、高度以及大小计算

        这里采取递归的方式

 void _Inorder(Node* root)
    {
        if (root == nullptr)
        {
            return;
        }
        _Inorder(root->_left);
        cout << root->_kv.first << ":" << root->_kv.second << endl;
        _Inorder(root->_right);
    }

    int _Height(Node* root)
    {
        if (root == nullptr)
            return 0;
        int leftHeight = _Height(root->_left);
        int rightHeight = _Height(root->_right);
        return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
    }
    bool _IsBalanceTree(Node* root)
    {
        if (nullptr == root)
                return true;
        
        int leftHeight = _Height(root->_left);
        int rightHeight = _Height(root->_right);
        int diff = rightHeight - leftHeight;
        if (abs(diff) >= 2)
        {
            cout << root->_kv.first << "高度差异常" << endl;
                return false;
        }
        if (root->_bf != diff)
        {
            cout << root->_kv.first << "平衡因子异常" << endl;
                return false;
        }
        return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);
    }

    int _size(Node* root)
    {
        if (root == nullptr)
        {
            return 0;
        }
        return _size(root->_left) + _size(root->_right) + 1;
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值