C++实现AVLTree

AVLTree就是平衡因子的绝对值不超过1的二叉搜索树,而平衡因子就是右子树的高度减去左子树的高度多得到的值,由二叉搜索树的性质我们可以知道,它比二叉搜索树的要求更为严格,因为二叉搜索树如果遇到的是一个特殊的有序的序列,那么二叉搜索树就会退化成一个链表,如图:
这里写图片描述

此时,二叉搜索树的时间复杂度就是o(n),而AVLTree由于平衡因子的绝对值不超过1,所以,它的时间复杂度就是o(log n),这也是AVLTree的优点所在。

重点是TVLTree的平衡因子的保证,这就要在结点插入的时候将这棵树进行一个调平(旋转)操作,使得平衡因子的绝对值不超过1,比如上图的情况调平之后就是:
这里写图片描述
当然这只是一种情况,具体调平操作有四类:
(1)左单旋
这里写图片描述
(2)右单旋
这里写图片描述
(3)左右双旋(分两种)
这里写图片描述
(4)右左双旋(分两种)
这里写图片描述

代码实现:

#pragma once


template <class K,class V>
struct AVLTreeNode
{
    int _bf;         //平衡因子
    K _key;
    V _value;

    AVLTreeNode<K, V>* _left;
    AVLTreeNode<K, V>* _right;
    AVLTreeNode<K, V>* _parent;

    AVLTreeNode(const K& key,const V& value)
        :_bf(0)
        ,_key(key)
        ,_value(value)
        ,_left(NULL)
        ,_right(NULL)
        ,_parent(NULL)
    {}


};


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

    bool Insert(const K& key, const V& value)
    {
        //将结点插入

        //1.为空时直接新创建一个结点
        if (NULL == _root)
        {
            _root = new Node(key, value);
            return true;
        }
        else  //寻找插入位置
        {
            Node* cur = _root;
            Node* parent = NULL;
            while (cur)
            {
                // 左小又大
                if (key < cur->_key)
                {
                    parent = cur;
                    cur = cur->_left;
                }
                else if (key > cur->_key)
                {
                    parent = cur;
                    cur = cur->_right;
                }
                else
                    return false;
            }//出循环即为找到相应位置

            cur = new Node(key, value);

            //按照大小关系进行连接
            if (key < parent->_key)
            {
                parent->_left = cur;
                cur->_parent = parent;
            }
            else
            {
                parent->_right = cur;
                cur->_parent = parent;
            }

            //更新平衡因子
            while (parent)
            {


                if (cur == parent->_left)
                    parent->_bf--;   //插入节点在左侧,左树高度增加一,平衡因子减一
                else 
                    parent->_bf++;   //插入节点在右侧,右树高度增加一,平衡因子加一

                if (0 == parent->_bf)
                {
                    break;           // 插入后,平衡因子为零,不用调平
                }
                else if (1 == parent->_bf || -1 == parent->_bf)
                {
                    cur = parent;
                    parent = cur->_parent;  //插入后,平衡因子为1或-1,则继续想根结点更新
                }
                else 
                {
                    if (2 == parent->_bf)    //插入后,平衡因子为2,需要旋转(具体结合前面的图分析)
                    {
                        //1.左单旋
                        Node* subR = parent->_right;
                        if (1 == subR->_bf)
                        {
                            RotateL(parent);
                        }
                        //2.左右双旋
                        else
                        {
                            RotateRL(parent);
                        }
                    }
                    else if (-2 == parent->_bf)
                    {
                        //1.右单旋
                        Node* subL = parent->_left;
                        if (-1 == subL->_bf)
                        {
                            RotateR(parent);

                        }
                        //2.右左双旋
                        else
                        {
                            RotateLR(parent);
                        }
                    }
                    break;
                }

            }
            return true;
        }
        return false;
    }

    //中序遍历
    void InOrder()
    {
        _InOrder(_root);
        cout << endl;
    }

    bool IsBalance()   //检验是否平衡
    {
        int height = 0;
        return _IsBalance(_root, height);
    }
protected:

    // height 传引用的原因:要将每一层的结点个数加在一起
    bool _IsBalance(Node* root, int& height)
    {
        if (root == NULL)
        {
            height = 0;
            return true;
        }

        int left, right;
        if (_IsBalance(root->_left, left) && _IsBalance(root->_right, right)
            && abs(right - left) < 2)
        {
            height = left > right ? left + 1 : right + 1;

            if (root->_bf != right - left)
            {
                cout << "该结点平衡因子异常: " << root->_key << endl;
                return false;
            }

            return true;
        }
        else
        {
            return false;
        }
    }

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

        parent->_left = subLR;
        if (subLR)
            subLR->_parent = parent;

        subL->_right = parent;


        Node* ppNode = parent->_parent;
        parent->_parent = subL;

        if (NULL == ppNode)
        {
            _root = subL;
            subL->_parent = NULL;
        }
        else
        {
            if (ppNode->_left == parent)
                ppNode->_left = subL;
            else
                ppNode->_right = subL;

            subL->_parent = ppNode;
        }

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

    //左单旋
    void RotateL(Node* parent)
    {

        Node* subR = parent->_right;
        Node* subRL = subR->_left;

        parent->_right = subRL;
        if (subR)
            subR->_parent = parent;

        subR->_left = parent;

        Node* ppNode = parent->_parent;
        parent->_parent = subR;

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

            subR->_parent = ppNode;
        }

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

    void RotateLR(Node* parent)
    {
        Node* subL = parent->_left;
        Node* subLR = subL->_right;
        int bf = subLR->_bf;

        RotateL(subL);
        RotateR(parent);

        if (0 == bf)
        {
            subLR->_bf = parent->_bf = subL->_bf = 0;
        }
        else if (-1 == bf)
        {
            parent->_bf = 1;
            subL->_bf = subLR->_bf = 0;
        }
        else if (1 == bf)
        {
            parent->_bf = subLR->_bf = 0;
            subL->_bf = -1;
        }

    }

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

        RotateR(subR);
        RotateL(parent);

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

    }

    void _InOrder(Node* root)
    {
        if (NULL == root)
        {
            return;
        }
        _InOrder(root->_left);
        cout << root->_key << "  ";
        _InOrder(root->_right);
    }

protected:
    Node* _root;

};

测试用例1(简单):

void TestAVLTree1()
{
    AVLTree<int, int> t1;
    int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i)
    {
        t1.Insert(a[i], i);
        cout << a[i] << "结点IsBalance?  " << t1.IsBalance() << endl;

    }

    cout << "中序遍历:";
    t1.InOrder();
    cout << "t1 IsBalance?  " << t1.IsBalance() << endl;
}

运行结果:
这里写图片描述

测试用例2(复杂):

void TestAVLTree2()
{
    AVLTree<int, int> t2;
    int a1[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
    for (size_t i = 0; i < sizeof(a1) / sizeof(a1[0]); ++i)
    {
        t2.Insert(a1[i], i);
        cout<<a1[i]<<"结点IsBalance?  "<<t2.IsBalance()<<endl;
    }

    cout << "中序遍历:";
    t2.InOrder();
    cout << "t2 IsBalance?  " << t2.IsBalance() << endl;
}

运行结果:
这里写图片描述

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值