有关AVL树的平衡化旋转和插入

一、AVL树的概念
1、定义:一棵高度平衡的二叉搜索树,就是AVL树。
2、性质
(1) 它的左右子树均为AVL树
(2) 左子树和右子树的高度之差(简称平衡因子)的绝对值不超过1(-1、0、1)
3、平衡因子的计算方法:左右子树的高度差

二、AVL树的平衡化旋转
1、左单旋:插入的节点位于较高右子树的右侧(右右)
*******当插入节点f之后,a节点的平衡因子的绝对值为2,此时的树已不满足AVL树的性质,需要通过左单旋去调节平衡因子已达到树的平衡。(将c节点往上提,a节点往下放)
这里写图片描述
这里写图片描述
代码如下:

void RotateL(pNode pParent)
    {
        //先找双亲的右子树,右子树的左子树
        pNode pSubR = pParent->_pRight;
        pNode pSubRL = pSubR->_pLeft;

        //先处理pSubRL
        pParent->_pRight = pSubRL;

        if(pSubRL)
            pSubRL->_pParent = pParent;

        pSubR->_pLeft = pParent;
        pNode ppParent = pSubR->_pParent;
        pParent->_pParent = pSubR;

        if(pParent == _pRoot)
        {
            pSubR->_pLeft = pParent;
            pSubR->_pParent = NULL;
        }

        //判断pParent为左子树还是右子树
        else if(ppParent->_pLeft == pParent)
        {
            ppParent->_pLeft = pSubR;
        }

        else
        {
            ppParent->_pRight = pSubR;
        }
        pSubR->_pParent = ppParent;

        //更新平衡因子
        pParent->_bf = pSubR->_bf = 0;
    }

2、右单旋:插入的节点位于较高左子树的左侧(左左)
****当插入节点f之后,a节点的平衡因子的绝对值为2,此时的树已不满足AVL树的性质,需要通过右单旋去调节平衡因子已达到树的平衡。(将b节点往上提,a节点往下放)
这里写图片描述
这里写图片描述

void RotateR(pNode pParent)
    {
        //先找双亲的左子树,以及左子树的右子树
        pNode pSubL = pParent->_pLeft;
        pNode pSubLR = pSubL->_pRight;

        //先处理pSubLR
        pParent->_pLeft = pSubLR;

        if(pSubLR)
            pSubLR->_pParent = pParent;

        pSubL->_pRight = pParent;
        pNode ppParent = pSubL->_pParent;
        pParent->_pParent = pSubL;

        if(pParent == _pRoot)
        {
            pSubL->_pRight = pParent;
            pSubL->_pParent = NULL;
        }

        //判断pParent为左子树还是右子树
        else if(ppParent->_pLeft == pParent)
        {
1           ppParent->_pLeft = pSubL;
        }

        else
        {
            ppParent->_pRight = pSubL;
        }
        pSubL->_pParent = ppParent;

        //更新平衡因子
        pParent->_bf = pSubL->_bf = 0;
    }

3、左右双旋(先左单旋后右单旋):插入的节点位于较高左子树的右侧
*******当插入节点f之后,a节点的平衡因子的绝对值为2,此时的树已不满足AVL树的性质,需要通过左右单旋去调节平衡因子已达到树的平衡。先以b节点为根节点左单旋调节a的左子树的平衡,再去整体右单旋调节整个子树
这里写图片描述

void RotateLR(pNode pParent)
    {
        pNode pSubL = pParent->_pLeft;
        pNode pSubLR = pSubL->_pRight;

        RotateL(pParent);
        RotateR(pParent->_pLeft);    

        //更新平衡因子
        int bf = pSubLR->_bf;
        if(bf == 1)
            pSubL->_bf = -1;
        else if(bf == -1)
            pSubL->_bf = 1;
    }

4、右左双旋(先右单旋后左单旋):插入的节点位于较高右子树的左侧
**** 当插入节点f之后,a节点的平衡因子的绝对值为2,此时的树已不满足AVL树的性质,需要通过右左单旋去调节平衡因子已达到树的平衡。先以c节点为根节点右单旋调节a的右子树的平衡,再去整体左单旋调节整个子树

这里写图片描述

void RotateRL(pNode pParent)
    {
        pNode pSubR = pParent->_pRight;
        pNode pSubRL = pSubR->_pLeft;

        RotateR(pParent); 
        RotateL(pParent);    

        //更新平衡因子
        int bf = pSubRL->_bf;
        if(bf == 1)
            pSubR->_bf = -1;
        else if(bf == -1)
            pSubR->_bf = 1;
    }

三、AVL树的插入
算法如下:
1、若树为空,插入后即为根节点,插入后直接返回true
2、若树不为空,寻找要插入的位置(若在寻找过程中找到key,则插入失败返回false)
3、插入节点
4、调节平衡因子

注意:新节点的平衡因子为0,但其双亲pParent的平衡因子有三种情况:

  • (1)若pParent的平衡因子为0,即在pParent的较矮的子树上插入新节点,pParent此时是平衡的,但此时pParent到根节点路径上的各节点为根的子树的高度不变,即各个节点的平衡因子不变。不需要调节平衡因子
  • (2)若pParent的平衡因子的绝对值为1,则插入前的pParent的平衡因子为0,插入后以pParent为根的子树没有失去平衡,但该子树的高度发生增加,此时需要从pParent向根节点依次查看pParent的双亲的平衡因子
  • (3)步骤2更新平衡因子之后,若pParent的平衡因子的绝对值为2,新节点在较高的子树插入,需要做平衡化处理
  • (3.1)若pParent->_bt == 2,说明右子树高,设pParent的右子树为pSubR。当pSubR的平衡因子为1时,执行左单旋;当pSubR的平衡因子为-1时,执行右左双旋
  • (3.2)若pParent->_bt == -2,说明左子树高,设pParent的左子树为pSubL。当pSubL的平衡因子为-1时,执行右单旋;当pSubL的平衡因子为1时,执行左右双旋
  • 旋转后pParent为根的子树高度降低,无需继续向上查看

完整代码如下:

#include<math.h>
#include<iostream>
using namespace std;
template <class V, class K>
struct AVLTreeNode
{
      //给左右子树,  双亲结点
      AVLTreeNode<V,K>* _pLeft;
      AVLTreeNode<V,K>* _pRight;
      AVLTreeNode<V,K>* _pParent;
      K _key;        //关键码
      V _value;
      int _bf;      //平衡因子
      //构造函数
      AVLTreeNode(const K& key, const V& value)
            :_pLeft(NULL)
            ,_pRight(NULL)
            ,_pParent(NULL)
            ,_key(key)
            ,_value(value)
            ,_bf(0)
      {}
};
template <class V, class K>
class AVLTree
{
      typedef AVLTreeNode<V,K> Node;
      typedef Node* pNode;
public:
      //构造函数
      AVLTree()
            :_pRoot(NULL)
      {}
      //插入结点
      bool Insert(const K& key, const V& value)
      {
            //如果树为空,直接插入
            if(NULL == _pRoot)
            //创建新结点,让其等于搜索二叉树的根
            {
                  _pRoot = new Node(key, value);
                  return true;
            }

            else
            {
                  //树不为空,分情况
                  pNode pParent = NULL;
                  pNode pCur = _pRoot;
                  //插入结点
                  while(pCur)
                  {
                        if(key > pCur->_key)
                        {
                              pParent = pCur;
                              pCur = pCur->_pRight;
                        }
                        else if(key < pCur->_key)
                        {
                              pParent = pCur;
                              pCur = pCur->_pLeft;
                        }
                        else
                              return true;
                  }
                  pCur = new Node(key, value);
                  if(key > pParent->_key)
                  {
                        pParent->_pRight = pCur;
                        pCur->_pParent = pParent;
                  }
                  else
                  {
                        pParent->_pLeft = pCur;
                        pCur->_pParent = pParent;
                  }
                  //调节平衡因子
                  while(pParent)
                  {
                        if(pParent->_pLeft = pCur)
                        {
                              pParent->_bf--;
                        }
                        else
                        {
                              pParent->_bf++;
                        }
                        if(pParent->_bf == 0)
                              break;
                        else if(pParent->_bf == 1 || pParent->_bf == -1)
                        {
                              pCur = pParent;
                              pParent = pCur->_pParent;
                        }
                        else
                        {
                              if(pParent->_bf == 2)
                              {
                                    if(pCur->_bf == 1)
                                          RotateL(pParent);
                                    else   //-1
                                          RotateRL(pParent);
                              }
                              else
                              {
                                    if(pCur->_bf == -1)
                                          RotateR(pParent);
                                    else     //1
                                          RotateLR(pParent);
                              }
                        }
                        break;
                  }
            }
            return true;
      }
      void Inorder()
      {
            _Inorder(_pRoot);
            cout<<endl;
      }
      bool IsBalance()
      {
            return _IsBalance(pRoot);
      }
private:
      //左单旋---插入较高右子树的右侧
      void RotateL(pNode pParent)
      {
            //先找双亲的右子树,右子树的左子树
            pNode pSubR = pParent->_pRight;
            pNode pSubRL = pSubR->_pLeft;
            //先处理pSubRL
            pParent->_pRight = pSubRL;
            if(pSubRL)
                  pSubRL->_pParent = pParent;
            pSubR->_pLeft = pParent;
            pNode ppParent = pSubR->_pParent;
            pParent->_pParent = pSubR;
            if(pParent == _pRoot)
            {
                  pSubR->_pLeft = pParent;
                  pSubR->_pParent = NULL;
            }
            //判断pParent为左子树还是右子树
            else if(ppParent->_pLeft == pParent)
            {
                  ppParent->_pLeft = pSubR;
            }
            else
            {
                  ppParent->_pRight = pSubR;
            }
            pSubR->_pParent = ppParent;
            //更新平衡因子
            pParent->_bf = pSubR->_bf = 0;
      }
      //右单旋---插入较高左子树的左侧
      void RotateR(pNode pParent)
      {
            //先找双亲的左子树,以及左子树的右子树
            pNode pSubL = pParent->_pLeft;
            pNode pSubLR = pSubL->_pRight;
            //先处理pSubLR
            pParent->_pLeft = pSubLR;
            if(pSubLR)
                  pSubLR->_pParent = pParent;
            pSubL->_pRight = pParent;
            pNode ppParent = pSubL->_pParent;
            pParent->_pParent = pSubL;
            if(pParent == _pRoot)
            {
                  pSubL->_pRight = pParent;
                  pSubL->_pParent = NULL;
            }
            //判断pParent为左子树还是右子树
            else if(ppParent->_pLeft == pParent)
            {
                  ppParent->_pLeft = pSubL;
            }
            else
            {
                  ppParent->_pRight = pSubL;
            }
            pSubL->_pParent = ppParent;
            //更新平衡因子
            pParent->_bf = pSubL->_bf = 0;
      }
      //左右双旋---插入较高左子树的右侧(先左旋后右旋)
      void RotateLR(pNode pParent)
      {
            pNode pSubL = pParent->_pLeft;
            pNode pSubLR = pSubL->_pRight;
            RotateL(pParent);
            RotateR(pParent->_pLeft);   
            //更新平衡因子
            int bf = pSubLR->_bf;
            if(bf == 1)
                  pSubL->_bf = -1;
            else if(bf == -1)
                  pSubL->_bf = 1;
      }
      //右左双旋---插入较高右子树的左侧(先右旋后左旋)
      void RotateRL(pNode pParent)
      {
            pNode pSubR = pParent->_pRight;
            pNode pSubRL = pSubR->_pLeft;
            RotateR(pParent);
            RotateL(pParent);   
            //更新平衡因子
            int bf = pSubRL->_bf;
            if(bf == 1)
                  pSubR->_bf = -1;
            else if(bf == -1)
                  pSubR->_bf = 1;
      }
      void _Inorder(pNode pRoot)
      {
            if(NULL == pRoot)
                  return;
            _Inorder(pRoot->_pLeft);
            _Inorder(pRoot->_pRight);
      }
      bool _IsBalance(pNode pRoot)
      {
            //树为空
            if(NULL == pRoot)
                  return true;
            //树存在
            int leftHeight = _Height(pRoot->_pLeft);
            int rightHeight = _Height(pRoot->_pRight);

            if(abs(rightHeight - leftHeight) >= 2)
                  return false;
            return _IsBalance(pRoot->_pLeft)&&_IsBalance(pRoot->_pRight);
      }

      int _Height(pNode pRoot)
      {
            if(NULL == pRoot)
                  return 0;
            int leftHeight = _Height(pRoot->_pLeft);
            int rightHeight = _Height(pRoot->_pRight);
            return ((leftHeight>rightHeight?leftHeight:rightHeight)+1);
      }
protected:
      pNode _pRoot;
};
void AVLTreeTest()
{
      int array[] = {16, 3, 7, 11, 9, 26, 18, 14, 15};
      AVLTree<int, int> A;
      for(int i = 0; i<sizeof(array)/sizeof(array[0]); ++i)
      {
            A.Insert(array[i], i);
      }
      A.Inorder();
}
int main()
{
      void AVLTreeTest();
      return 0;
}

哈哈,有关AVL树的四种旋转的情况有多重,我只画了一部分,读者可以自行画出全部!!!

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值