数据结构:AVL树的平衡调整——LL,LR,RL,RR

AVL树的全称是平衡搜索二叉树,本质上也是一个二叉搜索树(BST),满足BST树的所有性质。

但是我们在使用二叉搜索树的时候,我们知道通常情况在BST中搜索一个节点的时间复杂度是O(lgn)。

最坏的情况为O(n),这种情况就是出现连续的左子树/右子树,如下图所示:

这种情况其实就已经是链式存储,无法将树的优势体现出来。

为了避免这种情况,我们就要保证这个树随时都是平衡的。当然要求不能那么严格,不需要保证它完全平衡(每个节点的左右子树高度差的绝对值都为0),AVL树就要求的是只要每个节点的左右子树高度差的绝对值不超过1,就可以称作平衡。

我们将“每个节点的左右子树的高度差的绝对值”叫做平衡因子(BF)。

在AVL树中,插入一个节点之后都会判断是否打破了这个平衡。如果打破了,就需要对树进行调整,让它仍然满足平衡的定义,并且不改变中序遍历的正确性。这步操作就叫做旋转。即,是否需要旋转以及具体的旋转实现都要包含在插入函数里。

 

根据插入的位置不同,旋转的类型也分为4种:LL,LR,RL,RR。

旋转的几种情况:
1.插入点位于x的左孩子的左子树中。	左左LL  右旋。
2.插入点位于x的左孩子的右子树中。	左右LR	较低的先左旋,转换为LL问题,再右旋。
3.插入点位于x的右孩子的左子树中。	右左RL	较低的先右旋,转化为RR问题。再左旋。
4.插入点威武x的右孩子的右子树中。	右右RR	左旋。

接下来我们就用几个简单的例子,来分析旋转操作。

先给出AVL树的定义。

typedef struct AVLTree
{
    int height;                //当前节点的高度。
    int data;
    struct AVLTree* lchild;
    struct AVLTree* rchild;
}Tree,*pTree
  1. LL & RR

如图所示。

原本的状态是左边图所示,中序遍历为2,3.此时平衡因子分别为1,0.

在插入了一个节点之后(此时我们还没有写带调整的插入函数,可以理解为使用BST树的插入函数),我们可以看到这就成了我们最不想看见的情况——变成了链式存储。此时,我们就需要进行调整了。

情况:导致失衡的节点(1)是节点node(3)的左子树的左孩子,即为LL情况。

具体算法如下:

1.对于节点node(值为3的节点),先取它的左孩子(值为2的节点)作为临时节点temp;

2.将temp的右孩子作为node的左孩子;

3.再将node作为temp的右孩子;

4.更新height

5.node = temp。此时,temp就成为了原来node一样的存在。

下图是调整后的二叉树:

可以看到,此时还是一个BST树且中序遍历的顺序也没有发生改变,还满足了AVL的要求。

具体代码实现:

前置函数:

int GetHeight(pTree tree)            //获取当前节点的高度。
{
    if(tree == nullptr) return 0;
    return tree->height;
}

bool IsBalanced(pTree tree)            //判断是否平衡。
{
    int BF = GetHeight(tree->lchild) - GetHeight(tree->rchild);
    return abs(BF) < 2;
}

LL型旋转函数:

pTree Rotate_LL(pTree tree)
{
    pTree temp = tree->lchild;
    tree->lchild = temp->rchild;
    temp->rchild = tree;

    //更新高度,先更新node再更新temp。
    tree->height = max(GetHeight(tree->lchild),GetHeight(tree->rchild))+1;
    temp->height = max(GetHeight(temp->lchild),GetHeight(temp->rchild))+1;

    return temp;
}

RR型由于和LL型是对称的,所以只需要将LL中的所有左右互换就可以了。

pTree Rotate_RR(pTree tree)
{
    pTree temp = tree->rchild;
    tree->rchild = temp->lchild;
    temp->lchild = tree;

    //更新高度,先更新node再更新temp。
    tree->height = max(GetHeight(tree->lchild),GetHeight(tree->rchild))+1;
    temp->height = max(GetHeight(temp->lchild),GetHeight(temp->rchild))+1;

    return temp;
}
  • LR & RL 

接下来分析LR型:

即,引起失衡的是node节点的左子树的右孩子。 即如下图的情况:

在节点值为4的节点插入5,是4的右孩子。此时已经失衡。即为LR问题。

LR具体算法:

1.先获取node(值为10的节点)的左孩子节点,记为temp。

2.对temp进行RR。

3.对node进行LL。

代码实现:

pTree Rotate_LR(pTree tree)
{
    pTree temp = tree->lchild;
    tree->lchild = Rotate_RR(temp);
    return Rotate_LL(tree);
}

由于RL和LR是对称的,同样只需将所有的R换成L即可。此处不再赘述。

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是用伪代码示例生成AVL树的算法: AVL树结构定义: ``` struct Node { int value; //节点值 int height; //节点高度 Node *left; //左子树指针 Node *right; //右子树指针 }; ``` 生成AVL树的算法: ``` //计算节点高度 int calcHeight(Node *node) { if (node == NULL) { return 0; } return max(calcHeight(node->left), calcHeight(node->right)) + 1; } //获取平衡因子 int getBalanceFactor(Node *node) { if (node == NULL) { return 0; } return calcHeight(node->left) - calcHeight(node->right); } //左旋转调整 Node *leftRotate(Node *node) { Node *newroot = node->right; node->right = newroot->left; newroot->left = node; //更新节点高度 node->height = max(calcHeight(node->left), calcHeight(node->right)) + 1; newroot->height = max(calcHeight(newroot->left), calcHeight(newroot->right)) + 1; return newroot; } //右旋转调整 Node *rightRotate(Node *node) { Node *newroot = node->left; node->left = newroot->right; newroot->right = node; //更新节点高度 node->height = max(calcHeight(node->left), calcHeight(node->right)) + 1; newroot->height = max(calcHeight(newroot->left), calcHeight(newroot->right)) + 1; return newroot; } //插入节点 Node *insert(Node *node, int value) { if (node == NULL) { node = new Node(); node->value = value; node->height = 1; node->left = node->right = NULL; return node; } if (value < node->value) { node->left = insert(node->left, value); } else if (value > node->value) { node->right = insert(node->right, value); } else { //已存在该节点 return node; } //更新节点高度 node->height = max(calcHeight(node->left), calcHeight(node->right)) + 1; //检查是否需要旋转调整 int balanceFactor = getBalanceFactor(node); if (balanceFactor > 1 && value < node->left->value) { //LL情况 return rightRotate(node); } else if (balanceFactor < -1 && value > node->right->value) { //RR情况 return leftRotate(node); } else if (balanceFactor > 1 && value > node->left->value) { //LR情况 node->left = leftRotate(node->left); return rightRotate(node); } else if (balanceFactor < -1 && value < node->right->value) {//RL情况 node->right = rightRotate(node->right); return leftRotate(node); } return node; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值