C++AVL树(2)

简介: C++AVL树(2)

四、AVL树的旋转


如果在一棵原本是平衡的AVL树中插入一个新节点,可能造成不平衡,此时必须调整树的结构,使之平衡


根据节点插入位置的不同,AVL树的旋转分为四种:

新节点插入较高右子树的右侧—右右:左单旋

1、左单旋

抽象示图:


注意:

上图在插入前AVL树是平衡的,新节点插入到60的右子树(注意:此处不是有孩子)中,60右子树增加了一层,导致以30为根的二叉树不平衡

要让30平衡,只能将30右子树的高度减少一层,左子树增加一层,即将右子树往上提,这样30转下来,因为30比60大=小,只能将其放在60的左子树,而如果60有左子树,左子树根的值一定大于30,小于60,只能将其放在30的右子树,旋转完成后,更新节点的平衡因子即可

对于a,b,c都是符合AVL树且高度为h的树的一种,这里不具体表示,以抽象表示各种情况,对于以下抽象图示也是如此

在旋转过程中,有以下几种情况需要考虑:

60节点的左孩子可能存在,也可能不存在


30可能是根节点,也可能是子树:如果是根节点,旋转完成后,要更新根节点;如果是子树,可能是某个节点的左子树,也可能是右子树,需要更新父结点的左右结点地址


旋转后,子树得到平衡,两个旋转结点的平衡因子更新为0,而高度没有改变,不用再向上更新结点平衡因子


实例示图:


实现代码:


// 左单旋
void RotateL(Node* parent)
{
    //记录节点信息
    Node* subR = parent->_right;
    Node* subRL = subR->_left;
    Node* parentP = parent->_parent;
    //修改链接关系
    parent->_right = subRL;
    if (subRL)//避免为空节点的情况
        subRL->_parent = parent;
    subR->_left = parent;
    parent->_parent = subR;
    //讨论父节点的情况
    if (parent == _root)
    {
        _root = subR;
        subR->_parent = nullptr;
    }
    else
    {
        if (parentP->_left == parent)
        {
            parentP->_left = subR;
        }
        else
        {
            parentP->_right = subR;
        }
        subR->_parent = parentP;
    }
    //更新平衡因子
    subR->_bf = parent->_bf = 0;
}


  1. 新节点插入较高左子树的左侧—左左:右单旋

2、右单旋

注:具体思路和步骤可以参考左单旋

  • 抽象示图:


  • 实例示图:

网络异常,图片无法展示
|


  • 实现代码:


// 右单旋
void RotateR(Node* parent)
{
    //记录节点信息
    Node* subL = parent->_left;
    Node* subLR = subL->_right;
    Node* parentP = parent->_parent;
    //修改链接关系
    parent->_left = subLR;
    if (subLR)//避免为空节点的情况
        subLR->_parent = parent;
    subL->_right = parent;
    parent->_parent = subL;
    //讨论父节点的情况
    if (parent == _root)
    {
        _root = subL;
        subL->_parent = nullptr;
    }
    else
    {
        if (parentP->_left == parent)
        {
            parentP->_left = subL;
        }
        else
        {
            parentP->_right = subL;
        }
        subL->_parent = parentP;
    }
    //更新平衡因子
    subL->_bf = parent->_bf = 0;
}


新节点插入较高左子树的右侧**—**左右:先左单旋再右单旋

3、左右双旋

抽象示图:


注意:

将双旋变成单旋后再旋转,即先对30进行左单旋,然后再对90进行右单旋,旋转完成后再考虑平衡因子的更新(并不都为0,具体情况具体分析)


复用单旋会把其他情况都给处理,例如子树是否为空,当前不平衡结点为根结点还是子树结点


对于h高度的子树,h满足大于等于0,当h=0时,插入新节点就是60


左右双旋可以看做是60做当前树的根结点,并将左子树给给30结点,将右子树给给90结点


旋转后更新平衡因子具有三种情况:

插入结点就是不平衡结点的subLR(左子结点的右子结点),30,60,90都更新为0


插入结点为不平衡结点的subLR的左子结点,30,60更新为0,90更新为1


插入结点就是不平衡结点的subLR的右子节点,90,60更新为0,30更新为-1


实例示图:h为0的情况


实现代码:


// 左右双旋
void RotateLR(Node* parent)
{
    //记录节点地址和平衡因子
    Node* subL = parent->_left;
    Node* subLR = subL->_right;
    int bf = subLR->_bf;
    //旋转
    RotateL(subL);
    RotateR(parent);
    //处理平衡因子
    if (bf == -1)//新增节点为subLR的左子树
    {
        subLR->_bf = 0;
        parent->_bf = 1;
        subL->_bf = 0;
    }
    else if (bf == 1)//新增节点为subRL的右子树
    {
        subL->_bf = -1;
        parent->_bf = 0;
        subLR->_bf = 0;
    }
    else if (bf == 0)//新增节点就是subRL
    {
        subLR->_bf = 0;
        parent->_bf = 0;
        subL->_bf = 0;
    }
    else //旋转之前就已经存在错误了
    {
        assert(false);
    }
}


4、右左双旋

  • 抽象示图:

网络异常,图片无法展示
|


注:具体情况可以参考左右双旋

  • 实例示图:


  • 实现代码:


// 右左双旋
void RotateRL(Node* parent)
{
    //记录节点地址和平衡因子
    Node* subR = parent->_right;
    Node* subRL = subR->_left;
    int bf = subRL->_bf;
    //旋转
    RotateR(subR);
    RotateL(parent);
    //处理平衡因子
    if (bf == -1)//新增节点为subLR的左子树
    {
        subRL->_bf = 0;
        parent->_bf = 0;
        subR->_bf = 1;
    }
    else if (bf == 1)//新增节点为subLR的右子树
    {
        subRL->_bf = 0;
        parent->_bf = -1;
        subR->_bf = 0;
    }
    else if (bf == 0)//新增节点就是subLR
    {
        subRL->_bf = 0;
        parent->_bf = 0;
        subR->_bf = 0;
    }
    else //旋转之前就已经存在错误了
    {
        assert(false);
    }
}
相关文章
|
18天前
|
存储 C++ 容器
c++的学习之路:26、AVL树
c++的学习之路:26、AVL树
27 0
|
1天前
|
存储 算法 C++
数据结构/C++:AVL树
数据结构/C++:AVL树
6 2
|
4天前
|
存储 机器学习/深度学习 算法
【C++入门到精通】C++入门 —— AVL 树(自平衡二叉搜索树)
【C++入门到精通】C++入门 —— AVL 树(自平衡二叉搜索树)
10 2
|
17天前
|
C++
【C++高阶(三)】AVL树深度剖析&模拟实现
【C++高阶(三)】AVL树深度剖析&模拟实现
|
1月前
|
机器学习/深度学习 算法 测试技术
【深度优先搜索】【树】【C++算法】2003. 每棵子树内缺失的最小基因值
【深度优先搜索】【树】【C++算法】2003. 每棵子树内缺失的最小基因值
|
2月前
|
存储 C++
【C++练级之路】【Lv.15】AVL树(双子旋转,领略绝对平衡之美)
【C++练级之路】【Lv.15】AVL树(双子旋转,领略绝对平衡之美)
【C++练级之路】【Lv.15】AVL树(双子旋转,领略绝对平衡之美)
|
2月前
|
存储 算法 数据库
【C/C++ 数据结构 】树的 四种表示方法
【C/C++ 数据结构 】树的 四种表示方法
31 0
|
2月前
|
存储 算法 C语言
【C/C++ 数据结构 树】探索C/C++中的二叉树:从理论到实践
【C/C++ 数据结构 树】探索C/C++中的二叉树:从理论到实践
63 0
|
2月前
|
存储 算法 C++
【C++ 包装器类 map】C++ 标准库(std)中的map结构 哈希表(unordered_map)和黑红树(map)教程
【C++ 包装器类 map】C++ 标准库(std)中的map结构 哈希表(unordered_map)和黑红树(map)教程
95 1
|
2月前
|
C++ 容器
【C++】—— 详解AVL树
【C++】—— 详解AVL树