AVL树

一、AVL树简介

(1)AVL树又称为高度平衡的二叉搜索树,是1962年有俄罗斯的数学家G.M.Adel’son-Vel’skii和E.M.Landis提出来的。
它能保持二叉树的高度平衡,尽量降低二叉树的高度,减少树的平均搜索长度;

(2)AVL树是既满足二叉搜索树的性质,同时又满足平衡树的性质(左右子树的高度差不超过1)

(3)AVL树的性质:
1>左子树和右子树的高度之差的绝对值不超过1
2>树中的每个左子树和右子树都是AVL树
3>每个节点都有一个平衡因子(balance factor–bf),任一节点的平衡因子是-1,0,1。
(每个节点的平衡因子等于右子树的高度减去左子树的高度)

(4)AVL树的插入/删除/查找的时间复杂度:
一棵AVL树有N个节点,其高度可以保持在log2N插入/删除/查找的时间复杂度也是O(log2N).
(ps:log2N是表示log以2为底N的对数)

二、AVL树的插入

在二叉搜索树中,插入一个元素,只需要找到该元素适合的位置,然后插入元素;但是AVL树是二叉树的升级;AVL树在插入一个元素时,不仅要找到元素的位置进行插入,而且还要在插入后,检查是否会影响树的高度;即会不会影响树的平衡性;如果不影响树的平衡性,则插入完毕;如果影响了树的平衡性则需要去调整结点,保持树的平衡性
下面一一分析:
(1)当插入一个结点之后,该节点的父节点的平衡因子bf变为0;说明该数此时依然是AVL树,不会对上层父节点产生影响,插入完毕,bf更新为0;

             5    添加9          5
         3      8 ------->   3      8
       2   4  6            2   4  6   9

(2)【该情况是直接插入节点后出现的情况】当插入一个结点之后,该节点的的父节点的bf变为1或者-1;说明该父节点之前的bf为0;插入该节点之后,影响了父节点的的树的平衡性;则一定会对上层的父节点产生影响;

循环更新上层的父节点的bf,假入上层父节点的bf更新完之后,
只是-1或者1,那么一直循环向上更新,直到父节点为停止,插入完毕;

如果上层父节点bf变为2或者-2;则要进行旋转,从而调整树的高度的平衡,更新结点的bf;插入完毕【即就是下面的第三种情况】;

(3)【该情况一定是循环向上更新父节点出现的】如果插入一个结点之后,该节点的父节点的bf变为-2或者2,那么要进行旋转,调整树的高度;更新结点的bf;

(4)不可能出现插入节点之后,其父节点变为3或者-3,因为,在插入之前,该数是一颗正确的AVL树,每个结点的bf
只能是0,1,-1三种;

注:旋转是为了降低树的高度,使AVL树保持平衡;
旋转时必须遵循规则是,旋转之后,该数依然是平衡树和搜索树(即高度平衡的AVL树);
旋转是以最先bf变为2或者-2的结点为起点进行旋转;
旋转分为四大类

(1)右单旋:向右旋转,左边的高度大于右边的高度;father->bf=-2,subL->bf=-1;

这里写图片描述

//右旋------✔
    void RotateR(Node* father)
    {
        Node* SubL=father->_left;
        Node* SubLR=SubL->_right;
        Node* PPNode=father->_father;
        //1.链接subLR和father
        father->_left=SubLR;
        if (SubLR)
        {
            SubLR->_father=father;
        }
        //2.链接SubL和PPNode,分两种情况
    //2.1  ppNode为空,直接将SubL变为_root,将SubL的father指向PPnode     
        if (PPNode==NULL)
        {
            _root=SubL;
            SubL->_father=PPNode;
        }
        //2.PPnode不为空
        else
        {
            if (PPNode->_left==father)
            {
                PPNode->_left=SubL;
            }
            else
            {
                PPNode->_right=SubL;
            }
            SubL->_father=PPNode;
        }

        //3.链接father和SubL
         SubL->_right=father;
        father->_father=SubL;
        //4.更新旋转以后的父节点和SubL的bf,因为father的左子树变了,所以bf回变,SubL的右子树变了所以bf会变
        father->_bf=0;
        SubL->_bf=0;
    }

(2)左单旋:向左旋转,右边的高度大于左边的高度;father->bf=2; subR=1;
这里写图片描述

//左旋------✔
    void RotateL(Node* father)
    {
        Node* SubR=father->_right;
        Node* SubRL=SubR->_left;
        Node* PPNode=father->_father;
        //1.链接SubRL和father
        father->_right=SubRL;
        if (SubRL)
        {
            SubRL->_father=father;
        }
        //2.链接PPNode和SubR,分两种情况
        //2.1PPNode为空
        if (PPNode==NULL)
        {
            _root=SubR;
            SubR->_father=PPNode;
        }
        //2.2ppNode不为空
        else
        {
            if (PPNode->_left==father)
            {
                PPNode->_left=SubR;
            }
            else
            {
                PPNode->_right=SubR;
            }
            SubR->_father=PPNode;
        }
       //3.链接father和SubR
        SubR->_left=father;
        father->_father=SubR;
        //4.更新平衡 因子
        father->_bf=0;
        SubR->_bf=0;
    }

(3)左右双旋:先左旋,后右旋;
这里写图片描述

//左右旋转------✔
    void RotateLR(Node* father)
    {
         Node* SubL=father->_left;
         Node* SubLR=SubL->_right;
         int bf=SubLR->_bf;
         //1.先以SubL左旋
         RotateL(SubL);
         //2.再以father右旋
         RotateR(father);


         //3.根据SubLR->_bf原始的bf更新旋转之后各个结点的bf
         if (bf==1)
         {
             SubL->_bf=-1;
             father->_bf=0;
         }
         else if (bf==-1)
         {
             father->_bf=1;
             SubL->_bf=-1;
         }
         else
         {
             SubL->_bf=0;
             father->_bf=0;
         }
         SubLR->_bf=0;
    }

(4)右左双旋:先右旋,后左旋
这里写图片描述

    //右左旋转------✔
    void RotateRL(Node* father)
    {
        Node* SubR=father->_right;
        Node* SubRL=SubR->_left;
        int bf=SubRL->_bf;
        //1.先以SubR右旋
        RotateR(SubR);
        //2.在以father左旋
        RotateL(father);

        //3.根据SubRL的原始bf更新旋转以后的各节点bf
        if(bf==1)
        {
             father->_bf=-1;
             SubR=0;
        }
        else if (bf==-1)
        {
            SubR->_bf=1;
            father->_bf=0;
        }
        else
        {
            SubR->_bf=0;
            father->_bf=0;
        }
        SubRL->_bf=0;
    }

AVL树的插入代码:

bool Insert(const K& key,const V& value)//AVL树的插入
    {
       //1.AVL树为空,直接插入
       if (_root==NULL)
       {
           _root=new Node(key,value);
           return true;
       }
       //2.AVL树不为空

       //2.1先找到要插入的位置
       Node* cur=_root;//记录要插入节点的位置
       Node* father=_root;//记录要插入节点的父节点
       while (cur)
       {
           //key已经存在,不用插入,直接返回
           if (cur->_key==key)
           {
                return false;
           }
           //key大于根结点
           else if (cur->_key<key)
           {
               father=cur;
               cur=cur->_right;
           }
           //key小于根结点
           else
           {
               father=cur;
               cur=cur->_left;
           }
       }

       //2.2cur找到插入的正确的位置,开始插入
       cur=new Node(key,value);
       //2.2.1插入右边,father->bf加1
       if (key>father->_key)
       {
           father->_right=cur;
           cur->_father=father;
       }
       //2.2.2插入左边,bf减1
       else
       {
           father->_left=cur;
           cur->_father=father;
       }

       //2.3更新父节点平衡因子,并判断是否需要调整树高度,让AVL树保持平衡
       while(father)
       {  
           //2.3.1更新平衡因子
           //1>插入左边  bf减1
           if (father->_left==cur)
           {
               father->_bf-=1;
           }
           //2>插入右边  bf加1
           if (father->_right==cur)
           {
               father->_bf+=1;
           }
           //2.3.2根据更新的平衡因子,判断是否需要调整树的高度

           //1>插入一个结点之后,父节点的平衡因子更新为0;不影响树的高度,无需调整,插入完毕
           if (father->_bf==0)
           {
               return true;
           }
           //2>(直接插入影响)父节点的平衡因子更新为1或者-1,影响树的高度,那么会对上层父节点的平衡因子产生影响;继续判断上层父节点的bf更新
           else if (father->_bf==-1||father->_bf==1)
           {
                cur=father;
                father=father->_father;
           }
           //3>(循环判断得到)当父节点的平衡因子更新为2或者-2,影响树的高度,这时AVL树的平衡被破坏,那么需要旋转调整降低树的高度
           else if (father->_bf==-2||father->_bf==2)
           {
               //3.1>左旋
               if(father->_bf==2&&cur->_bf==1)
               {
                    RotateL(father);
                    return true;
               }
               //3.2>右旋
               if(father->_bf==-2&&cur->_bf==-1)
               {
                    RotateR(father);
                    return true;
               }
               //3.3>左右双旋
               if (father->_bf==-2&&cur->_bf==1)
               {
                    RotateLR(father);
                    return true;
               }
               //3.4>右左双旋
               if (father->_bf==2&&cur->_bf==-1)
               {
                    RotateRL(father);
                    return true;
               }  
           }
           //4>父节点的平衡因子出现其他情况都是错误的,说明插入之前,这颗树就不是AVL树; 
           else
           {
               cout<<"平衡因子异常"<<endl;
           }
       }
    }

三、AVL树的删除

AVL树的删除比较复杂;具体过程是这样的:
首先先通过Key值找到相应的结点;
1.如果AVL树为空,不用找了,直接返回查找失败;

2.AVL树不为空,然后找到了相应的结点;那么有以下几个情况;
2.1如果要删除的结点是叶子节点,则直接删除,然后根据删除结点时父节点的左右那个子节点来更新父节点的bf;并将父节点相应的指针置为空;

2.2如果要删除的结点只有一个子树(或左或右),那么先判断这个子树是删除结点左还是右,然后在判断删除结点是父节点的左还是右,然后根据这些信息,将删除结点的左或者右子树挂到其父节点相应的指针上;然后删除要删除的结点;通过判断挂在父节点的左右那个子树来更新父节点的bf;

3.如果要删除的结点左右子树都有,那么首先,先要找到要删除结点的右子树上的最小结点,即就是右子树的最左结点;然后将要删除的节点和找到的右子树的最小结点交换值;最后将最小结点删除,删除最小结点的时候,又要判断最小结点是否是叶子节点,如果是叶子节点,则直接删除,然后根据最小结点时父节点的左右那个孩子,来更新父节点的bf;如果不是叶子节点,则说明最小结点右子树不为空,则将最小结点的右子树挂在父节点上,这时又要判断改最小结点是父节点的左右那个孩子,除了最小结点为要删除的右子树的根结点时,最小结点为父节点(此时的父节点就是要一开始要删除的结点)的右子树以外,其他情况最小结点都是父节点的左子树;从而来更新最小结点(此时就是通过交换之后要删除的结点)的父节点的bf;

4.最后通过判断父节点的bf从而来调整树的高度或者向上更新父节点bf判断是否需要调整树的高度;

删除的时候在调整树的高度时和插入时的判断不一样;
【插入时】,在判断是否调整树的高度的条件是:
当插入一个结点后father的bf变为0,那么这个树的高度没有改变,不用调整;

当插入一个结点后当father的bf变为-1或者1时,这个树的高度有可能增加,所以必须向上更新父节点的bf,在更新的时候,如果发现父节点的bf变为2或者-2,就要通过旋转调整树的高度;如果一直更新到整棵树的根结点都没有发现bf为2或者-2 的情况出现,那么就不用通过旋转调整树的高度;

【删除时】,在判断是否需要调整的条件是:
当删除一个结点后,该节点的父节点的bf变为0,这时树的整体高度可能改变了;那么就要向上更新父节点bf,当出现父节点的bf为2或者-2 时,就需要通过旋转调整树的高度;

当删除一个结点之后,该节点的父节点的bf变为1或者-1,这时这棵树的整体高度没有改变,不同向上判断父节点的bf,直接就删除完毕;

总体删除的思想时:找—>删—>更新父节点bf—–>通过父节点bf判断是否调整树的高度或者继续向上更新bf以后判断是否需要调整树的高度

AVL树的删除代码:

    bool Remove(const K& key)//删除AVL树上某个结点值---树中的每个结点的key是唯一的
    {
        //1.如果树为空,删除失败
        if (_root==NULL)
        {
            return false;
        }
        //2.如果树不为空
        Node* cur=_root;
        Node* father=NULL;//始终记录要删除结点的父节点
        Node* del=NULL;//记录要删除的结点
        //2.1循环寻找要删除的结点位置
        while (cur)
        {
            //2.1.1key大于向右找
            if (key>cur->_key)
            {
                father=cur;
                cur=cur->_right;
            }
            //2.1.2key小于向左找
            else  if (key < cur->_key)
            {
                father=cur;
                cur=cur->_left;
            }
            //2.1.3找到了
            else
            {
                //1.要删除的结点是叶子节点
                if (cur->_left==NULL&&cur->_right==NULL)
                {
                    //1.1要删除的结点不是跟结点
                //1.1.1要删除的结点时父节点的左孩子,则删除以后父节点的bf增加1
                    if (father&&father->_left==cur)
                    {
                        father->_left=NULL;
                        father->_bf++;
                    }
                //1.1.2要删除的结点时父节点的右孩子,则删除以后父节点的bf减1
                    else if (father&&father->_right==cur)
                    {
                        father->_right=NULL;
                        father->_bf--;          
                    }
                    //1.2要删除的结点是根结点father==NULL&&cur==_root
                    else
                    {
                        cur->_father=NULL;
                    }
                    del=cur;//del记录要删除的节点
                }
                //2.要删除的结点只有一个子树
                else if (cur->_left==NULL||cur->_right==NULL)
                {
                    //2.1要删除的结点只有左子树且不是根结点
                    if (father&&cur->_left)//father!=NULL&&cur->_left!=NULL&&cur->_right==NULL
                    {
                        //2.1.1要删除的结点时父节点的左子树
                       if (father->_left==cur)
                       {
                           father->_left=cur->_left;
                           father->_bf++;
                       }
                       //2.1.2要删除的结点是父节点的右子树
                       else //father->_right==cur
                       {
                           father->_right=cur->_left;                          
                           father->_bf--;
                       }
                       del=cur;//del记录要删除的节点
                    }
                    //2.2要删除的结点只有右子树且不是根结点
                    else if (father&&cur->_right)//father!=NULL&&cur->_left=NULL&&cur->_right!=NULL
                    {
                        //2.2.1要删除的结点是父节点的左孩子
                        if (father->_left==cur)
                        {
                            father->_left=cur->_right;
                            father->_bf++;
                        }
                        //2.2.2要删除的结点是父节点的右孩子
                        else//father->_right==cur
                        {
                            father->_right=cur->_right;                         
                            father->_bf--;
                        }
                        del=cur;//del记录要删除的节点
                    }
                    //2.3要删除的结点是根结点
                    else//father==NULL 
                    {
                        //2.3.1要删除的结点是根结点,且根结点只有左子树
                        if(cur->_left)//father==NULL&&cur=_root&&cur->_left!=NULL&&cur->_right==NULL
                        {
                            _root=cur->_left;
                            _root->_bf=0;
                        }
                        //2.3.2要删除的结点是根结点且根结点只有右子树
                        else//father==NULL&&cur=_root&&cur->_left&&cur->_right!=NULL
                        {
                           _root=cur->_right;
                           _root->_bf=0;  
                        }
                        del=cur;//del记录要删除的节点
                    } 
                }
                //3.要删除的结点左右子树都有
                else//cur->_left&&cur->_right
                {
                    //3.1寻找要删除的结点的右子树的最小结点(即右子树的中序遍历的第一个结点)
                    Node* RightMin=cur->_right;//记录要删除节点的右子树的最小结点
                    father=cur;
                    while (RightMin->_left)
                    {
                        father=RightMin;
                        RightMin=RightMin->_left;
                    }
                    std::swap(cur->_key,RightMin->_key);
                    std::swap(cur->_value,RightMin->_value);
                    //3.1寻找的要删除的结点的右子树的最小结点不是右子树的根结点
                    if (father->_left=RightMin)
                    {
                        father->_left=RightMin->_right;
                        father->_bf++;
                    }
                    //3.2寻找的要删除的结点的右子树的最小结点是右子树的根结点
                    else//Father->_right=RightMin
                    {
                        father->_right=RightMin->_right;
                        father->_bf--;

                    }
                    del=RightMin;//del记录要删除的节点                  
                } 

                //根据父节点的bf调整AVL使其保持平衡
                while(father)
                {
                    cur=del;
                    if (father->_left==cur)
                    {
                        father->_bf++;
                    }
                    if (father->_right==cur)
                    {
                        father->_bf--;
                    }
                    //【直接删除造成父节点bf变为0】如果删除某个结点之后,father的bf为0,说明以前father的bf为1或-1,那么当bf变为0,树的高度改变,可能会对上层造成影响
                    //高度改变
                    if (father->_bf==0)
                    {
                        cur=father;
                        father=father->_father;//向上更新
                    }
                    //如果删除某个结点以后father的结点bf变为1或者-1,树的高度没有改变,那么不会对上层树的平衡造成影响,删除完成
                    //高度没有改变
                    else if (father->_bf==-1||father->_bf==1)
                    {
                        break;
                    }
                    //【向上循环更新bf变为2或者-2】当更新以后father的bf变为2或者-2,则要进行旋转,调整树的高度,保持树的平衡
                    else if(father->_bf==2||father->_bf==-2)
                    {
                        //3.1>左旋
                        if(father->_bf==2&&cur->_bf==1)
                        {
                            RotateL(father);
                            return true;
                        }
                        //3.2>右旋
                        if(father->_bf==-2&&cur->_bf==-1)
                        {
                            RotateR(father);
                            return true;
                        }
                        //3.3>左右双旋
                        if (father->_bf==-2&&cur->_bf==1)
                        {
                            RotateLR(father);
                            return true;
                        }
                        //3.4>右左双旋
                        if (father->_bf==2&&cur->_bf==-1)
                        {
                            RotateRL(father);
                            return true;
                        }  

                    }
                    //更新以后father的bf变为其他值,说明在更新之前该节点的bf就有问题
                    else
                    {
                         cout<<"平衡因子出错"<<endl;
                    }
                }
                delete del;
                del=NULL;
                return true;
            }       
        }
        //2.2没找到
        return false;
    }

四、完整代码:

测试用例AVL树的插入过程:
这里写图片描述

#include<iostream>
using namespace  std;

template<class K,class V>
struct AVLTreeNode
{
    AVLTreeNode<K,V>* _left;
    AVLTreeNode<K,V>* _right;
    AVLTreeNode<K,V>* _father;

    K _key;
    V _value;

    int _bf;//平衡因子
    AVLTreeNode(const K& key,const V& value)
        :_left(NULL)
        ,_right(NULL)
        ,_father(NULL)
        ,_key(key)
        ,_value(value)
        ,_bf(0)//平衡因子取决于左右子树的高度差,一个新创结点没有左右子树,所以平衡一直是0
    {}
};

template<class K,class V>
class AVLTree
{
    typedef AVLTreeNode<K,V>  Node;
public:
    AVLTree()//构造函数
        :_root(NULL)
    {}
    ~AVLTree()//析构函数
    {
        _Destroy(_root);
    }

    void InOrder()//中序打印
    {
        _InOrder(_root);
    }
    int Depth()//求树的高度(或深度)
    {
        return _Depth(_root);
    }
    bool IsBalance()//判断是AVL树是否平衡(递归)---一般方法O(N^N)
    {
         return _IsBalance(_root);
    }
    //判断是AVL树是否平衡---优化方法
    //如果我们每一次遍历,都会带回树的高度,这样就会少遍历一次,时间复杂度是0(N)
    bool IsBalanceOP()
    {
         int hight=0;
         return _IsBalanceOP(_root,hight);
    }
    Node* Find(const K& key);//与BST(二插搜索树的查找一样),参考上一讲二插搜索树的查找
    bool Insert(const K& key,const V& value)//AVL树的插入
    {
       //1.AVL树为空,直接插入
       if (_root==NULL)
       {
           _root=new Node(key,value);
           return true;
       }
       //2.AVL树不为空

       //2.1先找到要插入的位置
       Node* cur=_root;//记录要插入节点的位置
       Node* father=_root;//记录要插入节点的父节点
       while (cur)
       {
           //key已经存在,不用插入,直接返回
           if (cur->_key==key)
           {
                return false;
           }
           //key大于根结点
           else if (cur->_key<key)
           {
               father=cur;
               cur=cur->_right;
           }
           //key小于根结点
           else
           {
               father=cur;
               cur=cur->_left;
           }
       }

       //2.2cur找到插入的正确的位置,开始插入
       cur=new Node(key,value);
       //2.2.1插入右边,father->bf加1
       if (key>father->_key)
       {
           father->_right=cur;
           cur->_father=father;
       }
       //2.2.2插入左边,bf减1
       else
       {
           father->_left=cur;
           cur->_father=father;
       }

       //2.3更新父节点平衡因子,并判断是否需要调整树高度,让AVL树保持平衡
       while(father)
       {  
           //2.3.1更新平衡因子
           //1>插入左边  bf减1
           if (father->_left==cur)
           {
               father->_bf-=1;
           }
           //2>插入右边  bf加1
           if (father->_right==cur)
           {
               father->_bf+=1;
           }
           //2.3.2根据更新的平衡因子,判断是否需要调整树的高度

           //1>插入一个结点之后,父节点的平衡因子更新为0;不影响树的高度,无需调整,插入完毕
           if (father->_bf==0)
           {
               return true;
           }
           //2>(直接插入影响)父节点的平衡因子更新为1或者-1,影响树的高度,那么会对上层父节点的平衡因子产生影响;继续判断上层父节点的bf更新
           else if (father->_bf==-1||father->_bf==1)
           {
                cur=father;
                father=father->_father;
           }
           //3>(循环判断得到)当父节点的平衡因子更新为2或者-2,影响树的高度,这时AVL树的平衡被破坏,那么需要旋转调整降低树的高度
           else if (father->_bf==-2||father->_bf==2)
           {
               //3.1>左旋
               if(father->_bf==2&&cur->_bf==1)
               {
                    RotateL(father);
                    return true;
               }
               //3.2>右旋
               if(father->_bf==-2&&cur->_bf==-1)
               {
                    RotateR(father);
                    return true;
               }
               //3.3>左右双旋
               if (father->_bf==-2&&cur->_bf==1)
               {
                    RotateLR(father);
                    return true;
               }
               //3.4>右左双旋
               if (father->_bf==2&&cur->_bf==-1)
               {
                    RotateRL(father);
                    return true;
               }  
           }
           //4>父节点的平衡因子出现其他情况都是错误的,说明插入之前,这颗树就不是AVL树; 
           else
           {
               cout<<"平衡因子异常"<<endl;
           }
       }
    }
    bool Remove(const K& key)//删除AVL树上某个结点值---树中的每个结点的key是唯一的
    {
        //1.如果树为空,删除失败
        if (_root==NULL)
        {
            return false;
        }
        //2.如果树不为空
        Node* cur=_root;
        Node* father=NULL;//始终记录要删除结点的父节点
        Node* del=NULL;//记录要删除的结点
        //2.1循环寻找要删除的结点位置
        while (cur)
        {
            //2.1.1key大于向右找
            if (key>cur->_key)
            {
                father=cur;
                cur=cur->_right;
            }
            //2.1.2key小于向左找
            else  if (key < cur->_key)
            {
                father=cur;
                cur=cur->_left;
            }
            //2.1.3找到了
            else
            {
                //1.要删除的结点是叶子节点
                if (cur->_left==NULL&&cur->_right==NULL)
                {
                    //1.1要删除的结点不是跟结点
                    //1.1.1要删除的结点时父节点的左孩子,则删除以后父节点的bf增加1
                    if (father&&father->_left==cur)
                    {
                        father->_left=NULL;
                        father->_bf++;
                    }
                    //1.1.2要删除的结点时父节点的右孩子,则删除以后父节点的bf减1
                    else if (father&&father->_right==cur)
                    {
                        father->_right=NULL;
                        father->_bf--;          
                    }
                    //1.2要删除的结点是根结点father==NULL&&cur==_root
                    else
                    {
                        cur->_father=NULL;
                    }
                    del=cur;//del记录要删除的节点
                }
                //2.要删除的结点只有一个子树
                else if (cur->_left==NULL||cur->_right==NULL)
                {
                    //2.1要删除的结点只有左子树且不是根结点
                    if (father&&cur->_left)//father!=NULL&&cur->_left!=NULL&&cur->_right==NULL
                    {
                        //2.1.1要删除的结点时父节点的左子树
                       if (father->_left==cur)
                       {
                           father->_left=cur->_left;
                           father->_bf++;
                       }
                       //2.1.2要删除的结点是父节点的右子树
                       else //father->_right==cur
                       {
                           father->_right=cur->_left;                          
                           father->_bf--;
                       }
                       del=cur;//del记录要删除的节点
                    }
                    //2.2要删除的结点只有右子树且不是根结点
                    else if (father&&cur->_right)//father!=NULL&&cur->_left=NULL&&cur->_right!=NULL
                    {
                        //2.2.1要删除的结点是父节点的左孩子
                        if (father->_left==cur)
                        {
                            father->_left=cur->_right;
                            father->_bf++;
                        }
                        //2.2.2要删除的结点是父节点的右孩子
                        else//father->_right==cur
                        {
                            father->_right=cur->_right;                         
                            father->_bf--;
                        }
                        del=cur;//del记录要删除的节点
                    }
                    //2.3要删除的结点是根结点
                    else//father==NULL 
                    {
                        //2.3.1要删除的结点是根结点,且根结点只有左子树
                        if(cur->_left)//father==NULL&&cur=_root&&cur->_left!=NULL&&cur->_right==NULL
                        {
                            _root=cur->_left;
                            _root->_bf=0;
                        }
                        //2.3.2要删除的结点是根结点且根结点只有右子树
                        else//father==NULL&&cur=_root&&cur->_left&&cur->_right!=NULL
                        {
                           _root=cur->_right;
                           _root->_bf=0;  
                        }
                        del=cur;//del记录要删除的节点
                    } 
                }
                //3.要删除的结点左右子树都有
                else//cur->_left&&cur->_right
                {
                    //3.1寻找要删除的结点的右子树的最小结点(即右子树的中序遍历的第一个结点)
                    Node* RightMin=cur->_right;//记录要删除节点的右子树的最小结点
                    father=cur;
                    while (RightMin->_left)
                    {
                        father=RightMin;
                        RightMin=RightMin->_left;
                    }
                    std::swap(cur->_key,RightMin->_key);
                    std::swap(cur->_value,RightMin->_value);
                    //3.1寻找的要删除的结点的右子树的最小结点不是右子树的根结点
                    if (father->_left=RightMin)
                    {
                        father->_left=RightMin->_right;
                        father->_bf++;
                    }
                    //3.2寻找的要删除的结点的右子树的最小结点是右子树的根结点
                    else//Father->_right=RightMin
                    {
                        father->_right=RightMin->_right;
                        father->_bf--;

                    }
                    del=RightMin;//del记录要删除的节点                  
                } 

                //根据父节点的bf调整AVL使其保持平衡
                while(father)
                {
                    cur=del;
                    if (father->_left==cur)
                    {
                        father->_bf++;
                    }
                    if (father->_right==cur)
                    {
                        father->_bf--;
                    }
                    //【直接删除造成父节点bf变为0】如果删除某个结点之后,father的bf为0,说明以前father的bf为1或-1,那么当bf变为0,树的高度改变,可能会对上层造成影响
                    //高度改变
                    if (father->_bf==0)
                    {
                        cur=father;
                        father=father->_father;//向上更新
                    }
                    //如果删除某个结点以后father的结点bf变为1或者-1,树的高度没有改变,那么不会对上层树的平衡造成影响,删除完成
                    //高度没有改变
                    else if (father->_bf==-1||father->_bf==1)
                    {
                        break;
                    }
                    //【向上循环更新bf变为2或者-2】当更新以后father的bf变为2或者-2,则要进行旋转,调整树的高度,保持树的平衡
                    else if(father->_bf==2||father->_bf==-2)
                    {
                        //3.1>左旋
                        if(father->_bf==2&&cur->_bf==1)
                        {
                            RotateL(father);
                            return true;
                        }
                        //3.2>右旋
                        if(father->_bf==-2&&cur->_bf==-1)
                        {
                            RotateR(father);
                            return true;
                        }
                        //3.3>左右双旋
                        if (father->_bf==-2&&cur->_bf==1)
                        {
                            RotateLR(father);
                            return true;
                        }
                        //3.4>右左双旋
                        if (father->_bf==2&&cur->_bf==-1)
                        {
                            RotateRL(father);
                            return true;
                        }  

                    }
                    //更新以后father的bf变为其他值,说明在更新之前该节点的bf就有问题
                    else
                    {
                         cout<<"平衡因子出错"<<endl;
                    }
                }
                delete del;
                del=NULL;
                return true;
            }       
        }
        //2.2没找到
        return false;
    }
protected:
    //中序打印----✔
    void _InOrder(Node* root)
    {
        if (root==NULL)
        {
            return ;
        }
        _InOrder(root->_left);
        cout<<root->_key<<":"<<root->_value<<"  ";
        _InOrder(root->_right);
    }
    //求树的高度---✔
    int _Depth(Node* root)
    {
        if (root==NULL)
        {
            return 0;
        }
        int LeftDepth= _Depth(root->_left);
        int RightDepth= _Depth(root->_right);
        return  LeftDepth > RightDepth? LeftDepth+1:RightDepth+1;
    }
    //判断AVL是否平衡----✔
    bool _IsBalance(Node* root)
    {
        //1.空树也是AVL树,也平衡
       if (root==NULL)
       {
           return true;
       }
       //2.非空树
       int LeftHight=_Depth(root->_left);//左树高度
       int RightHight=_Depth(root->_right);//右树高度
       //如果该节点的左树高度减右树高度不等于该节点的平衡因子,说明平衡因子出错
       if (RightHight-LeftHight!=root->_bf)
       {
          cout<<"平衡因子出错"<<endl;
       }
       //AVL平衡树说的是每一颗子树的左右高度差的绝对值都大于1。所以没课子树都要递归判断;
       return abs(RightHight-LeftHight)<2 && _IsBalance(root->_left) && _IsBalance(root->_right);
    }

    bool _IsBalanceOP(Node* root,int& hight)
    {
        if (root==NULL)
        {
            hight=0;
            return true;
        }
        int LeftHight,RightHight;

        if (_IsBalanceOP(root->_left,LeftHight)&&_IsBalanceOP(root->_right,RightHight))
        {
            hight=LeftHight>RightHight? LeftHight+1:RightHight+1;
            return abs(RightHight-LeftHight)<2;
        }
        else
        {
            return false;
        }
    }
    //销毁
    void _Destroy(Node* root)
    {
        if (root==NULL)
        {
            return ;
        }
        _Destroy(root->_left);
        _Destroy(root->_right);
        delete root;
        root=NULL;
    }
    //左旋------✔
    void RotateL(Node* father)
    {
        Node* SubR=father->_right;
        Node* SubRL=SubR->_left;
        Node* PPNode=father->_father;
        father->_right=SubRL;
        if (SubRL)
        {
            SubRL->_father=father;
        }
        if (PPNode==NULL)
        {
            _root=SubR;
            SubR->_father=PPNode;
        }
        else
        {
            if (PPNode->_left==father)
            {
                PPNode->_left=SubR;
            }
            else
            {
                PPNode->_right=SubR;
            }
            SubR->_father=PPNode;
        }

        SubR->_left=father;
        father->_father=SubR;

        father->_bf=0;
        SubR->_bf=0;
    }
    //右旋------✔
    void RotateR(Node* father)
    {
        Node* SubL=father->_left;
        Node* SubLR=SubL->_right;
        Node* PPNode=father->_father;
        father->_left=SubLR;
        if (SubLR)
        {
            SubLR->_father=father;
        }       
        if (PPNode==NULL)
        {
            _root=SubL;
            SubL->_father=PPNode;
        }
        else
        {
            if (PPNode->_left==father)
            {
                PPNode->_left=SubL;
            }
            else
            {
                PPNode->_right=SubL;
            }
            SubL->_father=PPNode;
        }

        SubL->_right=father;
        father->_father=SubL;
        father->_bf=0;
        SubL->_bf=0;
    }
    //左右旋转------✔
    void RotateLR(Node* father)
    {
         Node* SubL=father->_left;
         Node* SubLR=SubL->_right;
         int bf=SubLR->_bf;
         //1.先以SubL左旋
         RotateL(SubL);
         //2.再以father右旋
         RotateR(father);


         //3.根据SubLR->_bf原始的bf更新旋转之后各个结点的bf
         if (bf==1)
         {
             SubL->_bf=-1;
             father->_bf=0;
         }
         else if (bf==-1)
         {
             father->_bf=1;
             SubL->_bf=-1;
         }
         else
         {
             SubL->_bf=0;
             father->_bf=0;
         }
         SubLR->_bf=0;
    }
    //右左旋转------✔
    void RotateRL(Node* father)
    {
        Node* SubR=father->_right;
        Node* SubRL=SubR->_left;
        int bf=SubRL->_bf;
        //1.先以SubR右旋
        RotateR(SubR);
        //2.在以father左旋
        RotateL(father);

        //3.根据SubRL的原始bf更新旋转以后的各节点bf
        if(bf==1)
        {
             father->_bf=-1;
             SubR=0;
        }
        else if (bf==-1)
        {
            SubR->_bf=1;
            father->_bf=0;
        }
        else
        {
            SubR->_bf=0;
            father->_bf=0;
        }
        SubRL->_bf=0;
    }
private:
    Node* _root;
};
int main()
{
    AVLTree<int, int> tree1;
    int array1[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };
    for (int i = 0; i < sizeof(array1) / sizeof(array1[0]); ++i)
    {
        tree1.Insert(array1[i],array1[i]);
    }
    tree1.InOrder();
    cout<<endl;
    cout <<"IsBalance?"<< tree1.IsBalance() << endl;
    cout << "IsBalance?" << tree1.IsBalanceOP() << endl;
    tree1.Remove(16);//删除的是叶子节点
    tree1.Remove(3);//删除的是叶子节点
    tree1.Remove(7);//删除的结点只有一个子树
    tree1.Remove(11);//要删除的结点左右子树都有
    tree1.InOrder();
    tree1.Remove(9);
    tree1.Remove(26);
    tree1.Remove(18);
    tree1.Remove(15);
    cout<<endl;
    tree1.InOrder();
    cout<<endl;
    cout << "IsBalance?" << tree1.IsBalance() << endl;


    int array2[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };

    AVLTree<int, int> tree2;
    for (size_t i = 0;i<sizeof(array2) / sizeof(array2[0]);++i)
    {
        tree2.Insert(array2[i],array2[i]);
    }   
    tree2.InOrder();
    cout<<endl;
    cout << "IsBalance?" << tree2.IsBalance() << endl;
    cout << "IsBalance?" << tree2.IsBalanceOP() << endl;
    tree2.Remove(5);
    tree2.InOrder();

}

这里写图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值