2021- 10 -13 AVL树的平衡调整(有parent指针) 代码逻辑

AVL平衡调整步骤:
代码写的十分潦草而且没经过测试,看个乐,我认为应该重点看一下没有parent指针的版本,以及我认为这里重点在于理解过程。

  1. 插入结点

  2. 找到 插入节点的 的第一个 不平衡的 非父祖先结点
    2.1 循环遍历插入结点的祖先结点
    2.2 在遍历的同时判断该结点是否平衡
    2.3 平衡则更新当前结点的高度,为了下一次判断是否平衡,不平衡则进行平衡调整

  3. 平衡则进行平衡调整
    3.1 判断三个结点的位置关系(LL,RR,LR,RL)
    3.2 进行平衡
    3.3 维护结点指针
    如果是删除导致的结点失衡,在afteradd里把break去掉就可以,一直往上查找是否导致了新的祖先结点失衡,反复平衡
    而且无论是添加导致的失衡,还是删除导致的失衡,修复的过程都是找到失衡结点进行旋转,旋转的过程也是一样的,找两个更高的子树结点,判断LL,RR,进行调整
    更详细的也可以看看别人写的笔记
    !!!

****我犯的错误::有没有可能旋转涉及的三个结点不连在一起? 不可能
有没有可能LL RR LR RL之外的情况?? 不可能 ****
需要注意:旋转中涉及到的三个结点分别是:第一个失衡非父祖先结点,第一个失衡非父祖先结点的左子结点或右子结点,第一个失衡非父祖先结点的左子结点或右子结点的左子结点或右子结点
也就是说,我们旋转这个操作是针对失衡的那个祖先结点,涉及了三个连在一起的结点,而这三个结点不一定是插入结点本身也不一定是插入结点的父结点(除非插入结点和父结点就是和失衡结点连在一起的那种最简单结构),我初学时总是觉得这三个点可能不在一起,实际上是混淆了平衡调整的目的是对失衡那个结点的调整,而不一定是对插入结点处,因为插入结点可能本身在很大一颗平衡的AVL子树中。
所以旋转的结点是三个相连的结点,自然只有这四种情况
在这里插入图片描述

//!二叉搜索树的添加删除,搜索操作的时间复杂度跟树的高度有关,为O(h)(相比线性表的O(n)搜索以及添加的话)
//! 满二叉树的高度基本是logn,所以满的二叉搜索树的时间复杂度也接近O(logn)
//! 但是如果二叉搜索树建立的顺序,输入是一个有序数组的话,比如1,2,3,4,5,。。。n这样建立的二叉搜索树高度就等于n
//! 也就是最坏时间复杂度等于O(n),被称为二叉搜索树退化为链表
//! 所以我们要尽力维持时间复杂度在O(h)而不是O(n)

//! 平衡的概念:二叉树结点数量固定,左右子树高度越接近就越平衡,完全二叉树和满二叉树是最平衡的

//! 所以如何改进我们的二叉搜索树??
//! 1.改变添加删除的元素顺序,简介控制树的高度   2.改善添加元素后的二叉树,使之更平衡
//! 我们设计的二叉搜索树是给别人用的,所以添加删除的顺序,我们无法改变,所以我们只能从添加后的二叉树的平衡改进入手
//! 一颗达到适度平衡的二叉搜索树 ,我们称之为平衡二叉搜索树  比如:AVL树,红黑树
//! AVL树是以其发明者命名的,发明者是一个苏联科学家,AVL树是最早发明的自平衡二叉搜索树之—,搜索、添加、删除的时间复杂度是O(logn)O(logn)
//! 平衡因子:该结点平衡因子等于左子树高度减去右子树高度,绝对值小于等于1,即超过1或小于-1,即为失衡,就要自动调整
#include <iostream>
#include "queue"
#include "stack"
#include <string>
#include <algorithm>
using namespace std;
class AVLNode
{
public:
    int element;
    int height;
    AVLNode *left;
    AVLNode *right;
    AVLNode *parent;
    AVLNode()
    {
        this->element = 0;
        this->left = nullptr;
        this->right = nullptr;
        this->parent = nullptr;
        this->height = 1;
    }
    AVLNode(int element)
    {
        this->element = element;
        this->left = nullptr;
        this->right = nullptr;
        this->parent = nullptr;
        this->height = 0;
    }
};

class AVLtreeZH
{
private:
    int size;

public:
    //我这里把根节点写成public了,主要后面写一些函数可以方便点
    AVLNode *root = nullptr;
    void add(int element); //添加元素

    void afterAdd(AVLNode *node);         //! 添加后判断是否进行以及高度更新  //平衡步骤//什么时候更新结点高度
    bool isBalanced(AVLNode *node);       //! 判断一个结点是否平衡
    int balanceFactor(AVLNode *node);     //! 获取一个结点的平衡因子
    void balancing(AVLNode *node);        //! 如何判别平衡操作的类型(RR,LL,LR,RL)
    AVLNode *heigherChild(AVLNode *node); //!  返回左右子树中高度较高的那个子结点
    int getHeight(AVLNode *node);         //! 通过左右子树的height值,返回当前结点的高度
    void rotateRight(AVLNode *node1);     //! 以node1右旋
    void rotateLeft(AVLNode *node1);      //! 以node1左旋
};

void AVLtreeZH::afterAdd(AVLNode *node)
{
    while (node->parent != nullptr)
    {
        node = node->parent;
        if (isBalanced(node))
        {
            node->height = getHeight(node); //更新结点高度
            continue;
        }
        else
        {
            balancing(node);
            break; //如果是删除导致的结点失衡,这里把break去掉就可以了,一直往上查找是否导致了新的祖先结点失衡
        }
    }
}

void AVLtreeZH::balancing(AVLNode *node1)
{
    AVLNode *node2 = heigherChild(node1);
    AVLNode *node3 = heigherChild(node2);
    if (node2 == node1->left && node3 == node2->left)
    { //LL情况
    rotateRight(node1);
    }
    if (node2 == node1->left && node3 == node2->right)
    { //LR情况
    rotateLeft(node2);
    rotateRight(node1);
    }
    if (node2 == node1->right && node3 == node2->right)
    { //RR情况
    rotateLeft(node1);
    }
    if (node2 == node1->right && node3 == node2->left)
    { //RL情况
    rotateRight(node2);
    rotateLeft(node1);
    }
}

void AVLtreeZH::rotateRight(AVLNode *node1)
{
    AVLNode *node2 = heigherChild(node1);
    AVLNode *node3 = heigherChild(node2);
    AVLNode *noderoot = node1->parent;
    node1->left = node2->right; //核心就这两句
    node2->right = node1;

    node1->parent = node2; //维护父结点指针
    node2->parent = noderoot;
    if (node1->left != nullptr)
    {
        node1->left->parent = node1;
    }
    if (noderoot == nullptr)
    {
    }
    else if (node1 == noderoot->left)
    {
        node2 = noderoot->left;
    }
    else if (node1 == noderoot->right)
    {
        node2 = noderoot->right;
    }

    node1->height = getHeight(node1);
    node2->height = getHeight(node2);
    node3->height = getHeight(node3);
    if (noderoot != nullptr)
    {
        noderoot->height = getHeight(noderoot);
    }
}

void AVLtreeZH::rotateLeft(AVLNode *node1)
{
    //和右旋一个路子
}

bool AVLtreeZH::isBalanced(AVLNode *node) //判断结点是否平衡,其实就是看平衡因子绝对值有没有大于等于2
{
    int i = balanceFactor(node);
    if (i < -1 || i > 1)
    {
        return false;
    }
    else if (-1 <= i <= 1)
    {
        return true;
    }
}

int AVLtreeZH::getHeight(AVLNode *node)
{
    if (node->left->height >= node->right->height)
    {
        return (node->left->height + 1);
    }
    else
    {
        return (node->right->height + 1);
    }
}

int AVLtreeZH::balanceFactor(AVLNode *node)
{
    return getHeight(node->left) - getHeight(node->right);
}

AVLNode *AVLtreeZH::heigherChild(AVLNode *node)
{
    int leftheight;
    int rightheight;
    if (node->left == nullptr)
    {
        leftheight = 0;
    }
    if (node->right == nullptr)
    {
        rightheight = 0;
    }
    if (leftheight == 0 && rightheight == 0)
    {
        return nullptr;
    }
    if (leftheight > rightheight)
    {
        return node->left;
    }
    else if (leftheight < rightheight)
    {
        return node->right;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值