AVL树

AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。

AVL树是建立在二叉搜索树的基础之上的,因为二叉树搜索树有缺陷

这里写图片描述
当我们的二叉搜索树是如上图的样子,那么它是顺序查找,在它的最坏情况下 时间复杂度是O( N),在这种情况下如果我们数据特别多,那么效率太低。而这种问题是因为它的左右子树的高度差极度不平衡造成的。
为了解决这种问题因此引入了AVL树,AVL树自身也是满足搜索二叉树的性质的,只不过它在左右子树高度差不平衡的时候会进行调整

AVL树的性质
1. 左子树和右子树的高度之差的绝对值不超过1 2. 树中的每个左子树和右子树都是AVL树 3. 每个节点都有一个平衡因子(balance factor–bf),任一节点的平衡因子是-1,0,1。(每个节点的平衡因子等于右子树的高度减去左子 树的高度 )
而AVL树的插入和删除它的时间复杂度都是O(logN)

AVL树的插入操作
由于AVL树的插入需要插入节点的父亲的信息,因此AVL树要维护的是一个个具有三叉链结构的节点,而之前普通的搜索二叉树维护的只是一个二叉链结构的 节点
因此AVL树较为普通的搜索二叉树较难
1、父节点的|bf|==2进行旋转
2、父节点的|bf|==1高度增加,向上更新平衡因子
3、父节点的|bf|==0,停止更新平衡因子

对于旋转又分为4种情况:
1、左单旋
2、右单旋
3、左右双旋
4、右左双旋

1、左单旋:
这里写图片描述

左单旋的代码就可以根据上图写出来

    void RotateL( Node*&parent)
    {
        Node*SubR = parent->_right;
        Node*SubRL = SubR->_left;
        parent->_right = SubRL;
        if (SubRL)
        {
            SubRL->_parent = parent;
        }
        SubR->_left = parent;
        Node*ppNode = parent->_parent;
        parent->_parent = SubR;
        if (ppNode == NULL)
        {
            _root = SubR;
            _root->_parent = NULL;
        }
        else//考虑这个parent节点可能不是根节点
        {

            if (parent == ppNode->_left)
            {
                ppNode->_left = SubR;

            }
            else
            {
                ppNode->_right = SubR;

            }
            SubR->_parent = ppNode; 
        }
        parent->_bf = SubR->_bf = 0;
    }

2、右单旋:
这里写图片描述
右单旋的代码就可以根据上图写出来

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->_parent = SubL;
        if (ppNode == NULL)
        {
            _root = SubL;
            _root->_parent = NULL;
        }
        else
        {
            if (parent == ppNode->_left)
            {
                ppNode->_left = SubL;
            }
            else
            {
                ppNode->_right = SubL;
            }
            SubL->_parent = ppNode;
        }
        SubL->_bf = parent->_bf = 0;
    }

3、左右双旋
这里写图片描述

这里写图片描述

代码如下:

void RotateLR(Node*parent)
    {
       RotateL(parent->left);
        RotateR(parent);
    }

这个代码是有问题的没有考虑特殊情况
因此修改代码
这里写图片描述
这里写图片描述

    void RotateLR(Node*parent)
    {
        Node*SubL = parent->_left;
        Node*SubLR = SubL->_right;
        int Prebf = SubLR->_bf;
        RotateL(SubL);
        RotateR(parent);
        if (Prebf == -1)
        {
            SubL->_bf = 0;
            parent->_bf = 1;
        }
        else if (Prebf == 1)
        {
            SubL->_bf = -1;
            parent->_bf = 0;
        }
        else
        {
            parent->_bf = SubL->_bf = 0;
        }
        SubLR->_bf = 0;
    }

4、右左双旋
同左右双旋原理一样
代码如下

    void RotateRL(Node*parent)
    {
        RotateR(parent->_right);
        RotateL(parent);
    }

但是这个代码是有问题的没有考虑特殊情况
当然这幅图我们也只是考虑了新增节点之后10的平衡因子为1,同左右双旋一样还要考虑10为0或者1的情况(这样考虑是因为10的父亲的祖父的平衡因子会随着10的变化而变化
因此修改代码

这里写图片描述
这里写图片描述

void RotateRL(Node*parent)
    {
        Node*SubR = parent->_right;
        Node*SubRL = SubR->_left;
        int Prebf = SubRL->_bf;
        RotateR(SubR);
        RotateL(parent);
        if (Prebf == -1)
        {
            SubR->_bf = 1;
            parent->_bf = 0;
        }
        else if (Prebf == 1)
        {
            SubR->_bf = 0;
            parent->_bf = -1;
        }
        else
        {
            parent->_bf = SubR->_bf = 0;
        }
        SubRL->_bf = 0;
    }

完整代码:

#include<iostream>
#include<stdlib.h>
using namespace std;
template<class K,class V>
struct AVLTreeNode
{
    AVLTreeNode(const K &key,const V&value=0)
    :_left(NULL)
    , _right(NULL)
    , _parent(NULL)
    , _key(key)
    , _value(value)
    , _bf(0)
    {

    }
    AVLTreeNode<K,V>*_left;
    AVLTreeNode<K, V>*_right;
    AVLTreeNode<K, V>*_parent;
    K _key;
    V _value;
    int _bf;
};
template<class K,class V>
class AVLTree
{
    typedef AVLTreeNode<K, V> Node;
public:
    AVLTree()
        :_root(NULL)
    {

    }
    bool Insert(const K &key,const V&value)
    {
        if (_root == NULL)
        {
            _root = new Node(key, value);
            return true;
        }
        else
        {
            Node*cur = _root;
            Node*parent = NULL;
            while (cur)
            {
                if (cur->_key > key)//和BS一样
                {
                    parent = cur;
                    cur = cur->_left;
                }
                else if (cur->_key < key)
                {
                    parent = cur;
                    cur = cur->_right;
                }
                else
                {
                    return false;
                }
            }
            cur = new Node(key, value);
            if (key > parent->_key)
            {
                parent->_right = cur;
                cur->_parent = parent;
            }
            else
            {
                parent->_left = cur;
                cur->_parent = parent;
            }
            //节点插入完成
            //在插入节点之后进行平衡因子的调节,分情况进行处理
            while (parent)//一直到调整到根节点为空为止
            {
                if (cur == parent->_left)
                {
                    parent->_bf--;
                }
                else if (cur == parent->_right)
                {
                    parent->_bf++;

                }
                if (parent->_bf ==2||parent->_bf==-2)//进行旋转,旋转又分为4种
                {
                    if (parent->_bf == -2)
                    {
                        if (parent->_left->_bf == 1)
                        {
                            RotateLR(parent);
                            return true;
                        }
                        else if (parent->_left->_bf == -1)
                        {
                            RotateR(parent);
                            return true;
                        }
                    }
                    else
                    {
                        if (parent->_right->_bf == 1)
                        {
                            RotateL(parent);
                            return true;
                        }
                        else if (parent->_right->_bf == -1)
                        {
                            RotateRL(parent);
                            return true;
                        }
                    }
                }
                else if (parent->_bf == 1 || parent->_bf == -1)//继续向上调整
                {
                    cur = parent;
                    parent = parent->_parent;
                }
                else
                {
                    break;//停止更新
                }
            }
        }
        return true;
    }
    void RotateL( Node*&parent)
    {
        Node*SubR = parent->_right;
        Node*SubRL = SubR->_left;
        parent->_right = SubRL;
        if (SubRL)
        {
            SubRL->_parent = parent;
        }
        SubR->_left = parent;
        Node*ppNode = parent->_parent;
        parent->_parent = SubR;
        if (ppNode == NULL)
        {
            _root = SubR;
            _root->_parent = NULL;
        }
        else//考虑这个parent节点可能不是根节点
        {

            if (parent == ppNode->_left)
            {
                ppNode->_left = SubR;

            }
            else
            {
                ppNode->_right = SubR;

            }
            SubR->_parent = ppNode; 
        }
        parent->_bf = SubR->_bf = 0;
    }

    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->_parent = SubL;
        if (ppNode == NULL)
        {
            _root = SubL;
            _root->_parent = NULL;
        }
        else
        {
            if (parent == ppNode->_left)
            {
                ppNode->_left = SubL;
            }
            else
            {
                ppNode->_right = SubL;
            }
            SubL->_parent = ppNode;
        }
        SubL->_bf = parent->_bf = 0;
    }
    void RotateLR(Node*parent)
    {
        Node*SubL = parent->_left;
        Node*SubLR = SubL->_right;
        int Prebf = SubLR->_bf;
        RotateL(SubL);
        RotateR(parent);
        if (Prebf == -1)
        {
            SubL->_bf = 0;
            parent->_bf = 1;
        }
        else if (Prebf == 1)
        {
            SubL->_bf = -1;
            parent->_bf = 0;
        }
        else
        {
            parent->_bf = SubL->_bf = 0;
        }
        SubLR->_bf = 0;
    }
    void RotateRL(Node*parent)
    {
        Node*SubR = parent->_right;
        Node*SubRL = SubR->_left;
        int Prebf = SubRL->_bf;
        RotateR(SubR);
        RotateL(parent);
        if (Prebf == -1)
        {
            SubR->_bf = 1;
            parent->_bf = 0;
        }
        else if (Prebf == 1)
        {
            SubR->_bf = 0;
            parent->_bf = -1;
        }
        else
        {
            parent->_bf = SubR->_bf = 0;
        }
        SubRL->_bf = 0;
    }
    bool IsBalance()
    {
        int depth = 0;
        return  _IsBalance(_root);//判断是否为AVL树
    }
    void InOrder()//中序遍历并不能检测是否是AVL树
    {
        _InOrder(_root);
    }
    int Hight(Node*root)
    {
        if (root == NULL)
        {
            return 0;
        }
        int leftHight = Hight(root->_left);
        int rightHight = Hight(root->_right);
        return leftHight > rightHight ? (leftHight + 1) : (rightHight + 1);
    }
    bool _IsBalance(Node*root)//时间复杂度为n^2
    {
        if (root == NULL)
        {
            return true;
        }
        int leftHight = Hight(root->_left);
        int rightHight = Hight(root->_right);
        int sub = rightHight - leftHight;
        if (abs(sub)>1||(sub) != root->_bf)
        {
            cout<<"异常为"<<root->_key<<" "<<root->_bf << endl;
            return false;
        }
        return abs(rightHight - leftHight) < 2 && _IsBalance(root->_left) && _IsBalance(root->_right);
    }

        bool _IsBalancePost(Node*root, int &depth)//采用时间复杂度为O(N)的算法
    {
        if (root == NULL)
        {
            depth = 0;
            return true;
        }
        int LeftDepth;
        int RightDepth;
        if (!_IsBalancePost(root->_left, LeftDepth))
        {
            return false;
        }
        if (!_IsBalancePost(root->_right, RightDepth))
        {
            return false;
        }
        int diff = RightDepth - LeftDepth;
        if (diff > 1 || diff<-1||diff!=root->_bf)
        {
            cout << "平衡因子异常:";
            cout << root->_key<<" ,"<<root->_bf << endl;
            return false;
        }
        depth = RightDepth - LeftDepth>0 ? RightDepth+1 : LeftDepth +1;
        return true;
    }
protected:
    void _InOrder(Node*root)
    {
        if (root == NULL)
        {
            return;
        }
        _InOrder(root->_left);
        cout << root->_key << " ";
        _InOrder(root->_right);
    }
    Node*_root;
};
void FunTest1()
{
    //4, 2, 6, 1, 3, 5, 15, 7, 16, 14
    //{16, 3, 7, 11, 9, 26, 18, 14, 15}
    AVLTree<int, int>av;
    int arr[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    for (int i = 0; i<(sizeof(arr) / sizeof(arr[0]));i++)
    {
        av.Insert(arr[i],i);
        cout << av.IsBalance() << endl;
    }
    cout << "IsBalance is  ";

    av.InOrder();
}
void FunTest2()
{
    AVLTree<int, int>av;
    int arr[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };
    for (int i = 0; i<(sizeof(arr) / sizeof(arr[0])); i++)
    {
        av.Insert(arr[i],i);
        cout<<av.IsBalance()<<endl;
    }
    cout << "IsBalance is  ";
    av.InOrder();
}
int main()
{
    FunTest1();
    system("pause");
    return 0;


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值