ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

AVL 平衡树的旋转理解

2020-10-17 02:03:15  阅读:293  来源: 互联网

标签:插入 Height AVL K2 K1 平衡 旋转 Left


AVL 平衡树的完全代码见 https://www.cnblogs.com/fanlumaster/p/13824006.html
首先我们明确一个定义:平衡因子:树的一个节点的左、右子树的高度差称为该节点的平衡因子。一棵 AVL 树的平衡因子只能有 0、-1、1 三种取值。

单旋转

LL 情况下的单旋转

左边是旋转前,右边是旋转后

20201016203344

LL情况:插入一个新节点到根节点的左子树(Left)的左子树(Left),导致根节点的平衡因子由 1 变为 2,如上图,在根节点 \(k_2\) 的左子树的左边插入节点 \(X\),导致 \(k_2\) 的平衡因子由 1 变成了 2。

为使树恢复平衡,我们把 \(k_1\) 变成这棵树的新根节点,因为 \(k_2\) 大于 \(k_1\),所以把 \(k_2\) 置为 \(k_1\) 的右子树,而原本在 \(k_1\) 的右子树的 \(Y\) 大于 \(k_1\) 且小于 \(k_2\),所以我们需要把 \(Y\) 置为 \(k_2\) 的左子树。这样一来,这棵树就重新恢复平衡。

简单来讲,我们只需要把 \(k_1\) 给“拎”上去,然后再把 \(Y\) 转移到 \(k_2\) 的左子树的位置就可以了。

一个旋转样例:

20201017001043

代码:

/* This function can be called only if K2 has a left child */
/* Perform a rotate between a node (K2) and its left child */
/* Update heights, then return new root */
//  LL 单旋转
static Position
SingleRotateWithLeft(Position K2)
{
    Position K1;

    // 旋转操作
    K1 = K2->Left;
    K2->Left = K1->Right;
    K1->Right = K2;

    // 更新节点的高度
    K2->Height = Max(Height(K2->Left), Height(K2->Right)) + 1;
    K1->Height = Max(Height(K1->Left), K2->Height) + 1;

    return K1;  /* New root 新的根节点 */
}

RR 情况下的单旋转

20201016203735

RR情况:和上面的类似,相当于对称的情况。

简单理解就是,把 \(k_2\) 给“拎”上去,然后 \(Y\) 根据相应的情况转移到 \(k_1\) 的右子树位置上。

代码:

/* This function can be called only if K1 has a right child */
/* Perform a rotate between a node (K1) and its right child */
/* Update heights, then return new root */
// RR 单旋转
static Position
SingleRotateWithRight(Position K1)
{
    Position K2;

    // 旋转操作
    K2 = K1->Right;
    K1->Right = K2->Left;
    K2->Left = K1;

    // 更新节点高度
    K1->Height = Max(Height(K1->Left), Height(K1->Right)) + 1;
    K2->Height = Max(Height(K2->Right), K1->Height) + 1;

    return K2;  /* New root */
}

双旋转

LR 情况下的双旋转

20201016212009

结合上面的图解,可以发现,LR 情况下的双旋转其实是两个单旋转:

  • 先对 \(k_1\) 进行 RR 单旋转,即,把 \(k_2\) 给“拎”上来
  • 然后对 \(k_3\) 进行 LL 单旋转,即,把 \(k_2\) 给“拎”上来

代码:

/* This function can be called only if K3 has a left */
/* child and K3's left child has a right child */
/* Do the left-right double rotation */
/* Update heights, then return new root */
// LR 双旋转
static Position
DoubleRotateWithLeft(Position K3)
{
    /* Rotate between K1 and K2 */
    K3->Left = SingleRotateWithRight(K3->Left); // 先进行 RR 旋转

    /* Rotate between K3 and K2 */
    return SingleRotateWithLeft(K3); // 然后进行 LL 旋转
}

RL 情况下的双旋转

20201016213529

和 LR 类似,RL 情况下的双旋转也是两个单旋转:

  • 先对 \(k_3\) 进行 LL 单旋转,把 \(k_2\) 给“拎”上来
  • 然后对 \(k_1\) 进行 RR 单旋转,把 \(k_2\) 给“拎”上来

代码:

/* This function can be called only if K1 has a right */
/* child and K1's right child has a left child */
/* Do the right-left double rotation */
/* Update heights, then return new root */
// RL 双旋转
static Position
DoubleRotateWithRight(Position K1)
{
    /* Rotate between K3 and K2 */
    K1->Right = SingleRotateWithLeft(K1->Right);

    /* Rotate between K1 and K2 */
    return SingleRotateWithRight(K1);
}

插入 3,2,3,在插入 1 的时候进行 LL 单旋转

20201017001733

插入 5,RR 单旋转

20201017002430

插入 6,RR 单旋转

20201017002937

插入 7,RR 单旋转

20201017003945

插入 15,16,RL 双旋转

20201017005028

插入 14,RL 双旋转

20201017010143

插入 13,RR 单旋转

20201017011112

插入 12,LL 单旋转

20201017011736

插入 11,10,8,略过过程,其中,插入 11 和 10 都需要单旋转,插入 8 不需要旋转

20201017012240

插入 9,LR 双旋转

20201017013127

标签:插入,Height,AVL,K2,K1,平衡,旋转,Left
来源: https://www.cnblogs.com/fanlumaster/p/13829581.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有