AVL树的删除
- 导读
- 一、AVL树的删除步骤
- 二、AVL树的删除用例
-
- [2.1 用例1:删除结点不影响平衡](#2.1 用例1:删除结点不影响平衡)
- [2.2 用例2:最小不平衡子树中,孙子位于 LL](#2.2 用例2:最小不平衡子树中,孙子位于 LL)
- [2.3 用例3:最小不平衡子树中,孙子位于 LR](#2.3 用例3:最小不平衡子树中,孙子位于 LR)
- [2.4 用例4:最小不平衡子树中,孙子位于 RR](#2.4 用例4:最小不平衡子树中,孙子位于 RR)
- [2.5 用例5:最小不平衡子树中,孙子位于 RL](#2.5 用例5:最小不平衡子树中,孙子位于 RL)
- [2.6 用例6:最小不平衡子树向上传导](#2.6 用例6:最小不平衡子树向上传导)
- 结语

导读
大家好,很高兴又和大家见面啦!!!
在上一篇内容中我们介绍了AVL树插入操作中的平衡旋转技巧(LL、LR、RR、RL旋转)后,我们了解到旋转是维护AVL树平衡的核心机制。
然而,删除操作可能引发更复杂的不平衡问题,且这种不平衡可能沿父节点路径向上传导,需多次调整。
那么,如何系统处理AVL树的删除,确保树始终保持平衡?现在,让我们直接进入正文,逐步解析删除操作的具体实现。
一、AVL树的删除步骤
AVL树 的删除操作与 BST 的删除操作相似但又有所不同:
- 相同点:对删除结点的处理相同
- 不同点:会对失去平衡的 BST 进行平衡旋转恢复其平衡状态
下面我们就来熟悉一下 AVL树 的删除操作的具体步骤。AVL树 的删除操作可以总结为5步:
- 使用 BST 的方法对 AVL树 进行结点的删除操作
- 完成删除后,开始向上查找,找到第一个最小不平衡子树
- 若删除操作对 AVL树 的平衡性没有影响,则完成删除操作
- 若删除操作对 AVL树 的平衡性有影响,则进入第三步
- 找到 最小不平衡子树 的最高的 孩子 和 孙子
- 按照 孙子 的位置,对 最小不平衡子树 进行平衡旋转:
- 孙子 为 最小不平衡子树 的 左孩子 L L L 的 左子树 L L L ,即满足 L L LL LL 平衡旋转 ,则需要对 最小不平衡子树 进行一次 右单旋转 (L L LL LL 平衡旋转),使其恢复平衡
- 孙子 为 最小不平衡子树 的 左孩子 L L L 的 右子树 R R R ,即满足 L R LR LR 平衡旋转 ,则需要对 最小不平衡子树 的 左孩子 先进行一次 左单旋转 再对该 最小不平衡子树 进行一次 右单旋转 (L R LR LR 平衡旋转),使其恢复平衡
- 孙子 为 最小不平衡子树 的 右孩子 R R R 的 右子树 R R R ,即满足 R R RR RR 平衡旋转 ,则需要对 最小不平衡子树 进行一次 左单旋转 (R R RR RR 平衡旋转),使其恢复平衡
- 孙子 为 最小不平衡子树 的 右孩子 R R R 的 左子树 L L L ,即满足 R L RL RL 平衡旋转 ,则需要对 最小不平衡子树 的 右孩子 先进行一次 右单旋转 再对该 最小不平衡子树 进行一次 左单旋转 (R L RL RL 平衡旋转),使其恢复平衡
- 完成平衡旋转后,继续向上查找 最小不平衡子树 :
- 若 AVL树 的不平衡性没有向上传导,则完成删除
- 若 AVL树 的不平衡性向上传导,则回到第三步,直到整棵树恢复平衡
注:
若各位朋友对 BST 的删除操作不太熟悉,可以回顾:【数据结构】考研数据结构核心考点:二叉排序树(BST)全方位详解与代码实现
若各位朋友对 AVL树 的平衡旋转不太熟悉,可以回顾:【数据结构】考研数据结构核心考点:AVL树插入操作深度解析------从理论到实践的旋转平衡实现
二、AVL树的删除用例
为了更好的理解整个删除的过程,下面我们以具体的例子来进行删除演示:
2.1 用例1:删除结点不影响平衡
在下面这棵 AVL树 中,我们需要对结点 7 7 7 进行删除:
2
平衡因子: 0 1
平衡因子: 0 3
平衡因子: 0 6
平衡因子: 0 5
平衡因子: 0 7
平衡因子: 0 4
平衡因子: 0
根据 BST 的删除规则,我们可以直接对其进行删除:
2
平衡因子: 0 1
平衡因子: 0 3
平衡因子: 0 6
平衡因子: 1 5
平衡因子: 0 NULL 4
平衡因子: 0
可以看到,该结点的删除不影响整个树的平衡,因此完成删除;
2.2 用例2:最小不平衡子树中,孙子位于 LL
在下面这棵 AVL树 中,我们需要删除结点 78 78 78:
44
平衡因子: 1 32
平衡因子: 1 78
平衡因子: 1 18
平衡因子: 0 40
平衡因子: 0 6
平衡因子: 0 24
平衡因子: 0 65
平衡因子: 0 NULL
根据 BST 的删除规则,由于该删除结点只有一个孩子,因此完成删除后直接用其孩子替代该结点:
44
平衡因子: 2 32
平衡因子: 1 65
平衡因子: 0 18
平衡因子: 0 40
平衡因子: 0 6
平衡因子: 0 24
平衡因子: 0
当删除完该结点后,通过向上查找,我们找到了 最小不平衡子树 ,其根结点的值存储的值为 44 44 44 ,因此我们需要找到该结点最高的孩子 与孙子:
44
平衡因子: 2
h = 4 32
平衡因子: 1
h = 3 65
平衡因子: 0
h = 1 18
平衡因子: 0
h = 2 40
平衡因子: 0
h = 1 6
平衡因子: 0
h = 1 24
平衡因子: 0
h = 1
根结点最高的孩子为其 左孩子 (L ),其最高的孙子为其 左孩子 的 左子树 (L ),因此我们需要对其进行一次 右单旋转:
32
平衡因子: 0
h = 3 18
平衡因子: 0
h = 2 44
平衡因子: 0
h = 2 6
平衡因子: 0
h = 1 24
平衡因子: 0
h = 1 40
平衡因子: 0
h = 1 65
平衡因子: 0
h = 1
可以看到,在完成旋转后,这棵 BST 已经恢复了平衡,因此完成删除;
2.3 用例3:最小不平衡子树中,孙子位于 LR
在下面这棵 AVL树 中,我们需要删除结点 78 78 78:
44
平衡因子: 1 32
平衡因子: -1 78
平衡因子: 1 18
平衡因子: 0 40
平衡因子: 0 35
平衡因子: 0 42
平衡因子: 0 65
平衡因子: 0 NULL
和前一个例子一样,被删除的结点只有一个孩子,因此删除该结点后,直接用其孩子来顶替该结点的位置:
44
平衡因子: 2 32
平衡因子: -1 65
平衡因子: 0 18
平衡因子: 0 40
平衡因子: 0 35
平衡因子: 0 42
平衡因子: 0
删除该结点后,我们通过向上查找,找到第一棵 最小不平衡子树 ,其根结点为 44 44 44 。接下来我们需要找到该结点的最高的 孩子 和最高的 孙子 :
44
平衡因子: 2
h = 4 32
平衡因子: -1
h = 3 65
平衡因子: 0
h = 1 18
平衡因子: 0
h = 1 40
平衡因子: 0
h = 2 35
平衡因子: 0
h = 1 42
平衡因子: 0
h = 1
其最高的孩子为 左孩子 (L ),其最高的孙子为其 左孩子 的 右子树 (R ),因此我们需要对其 左孩子 先进行一次 左单旋转 ,再对其进行一次 右单旋转:
先对左孩子: 32
进行一次左单旋转
-> 44
平衡因子: 2
h = 4 40
平衡因子: 1
h = 3 65
平衡因子: 0
h = 1 32
平衡因子: 0
h = 2 18
平衡因子: 0
h = 1 35
平衡因子: 0
h = 1 42
平衡因子: 0
h = 1 NULL NULL 再对整棵树: 44
进行一次右单旋转
-> 40
平衡因子: 0
h = 3 32
平衡因子: 0
h = 2 44
平衡因子: 0
h = 2 42
平衡因子: 0
h = 1 65
平衡因子: 0
h = 1 18
平衡因子: 0
h = 1 35
平衡因子: 0
h = 1
完成旋转后,这棵 BST 已经恢复了平衡,因此完成删除;
2.4 用例4:最小不平衡子树中,孙子位于 RR
在下面这棵 AVL树 中,我们需要删除结点 32 32 32:
44
平衡因子: -1 32
平衡因子: -1 78
平衡因子: -1 NULL 40
平衡因子: 0 65
平衡因子: 0 85
平衡因子: 0 80
平衡因子: 0 93
平衡因子:0
在这棵 AVL树 中,被删除的结点只有一个孩子,因此删除该结点后,直接用其孩子来顶替该结点的位置:
44
平衡因子: -2 40
平衡因子: 0 78
平衡因子: -1 65
平衡因子: 0 85
平衡因子: 0 80
平衡因子: 0 93
平衡因子:0
删除完结点后,通过向上查找,我们找到了最小不平衡子树: 44 44 44,因此我们需要找到该棵树的最高的 孩子 和最高的 孙子:
44
平衡因子: -2
h = 4 40
平衡因子: 0
h = 1 78
平衡因子: -1
h = 3 65
平衡因子: 0
h = 1 85
平衡因子: 0
h = 2 80
平衡因子: 0
h = 1 93
平衡因子:0
h = 1
其最高的孩子为 右孩子 (R ),其最高的孙子为 右孩子 的 右子树 (R ),因此我们需要对该树进行一次 左单旋转 :
78
平衡因子: 0
h = 3 44
平衡因子: 0
h = 2 40
平衡因子: 0
h = 1 65
平衡因子: 0
h = 1 85
平衡因子: 0
h = 2 80
平衡因子: 0
h = 1 93
平衡因子:0
h = 1
完成旋转后,这棵 BST 已经恢复了平衡,因此完成删除;
2.5 用例5:最小不平衡子树中,孙子位于 RL
在下面这棵 AVL树 中,我们需要删除结点 32 32 32:
44
平衡因子: -1 32
平衡因子: -1 78
平衡因子: 1 NULL 40
平衡因子: 0 65
平衡因子: 0 85
平衡因子: 0 50
平衡因子: 0 72
平衡因子:0
由于该结点只有一个孩子,根据 BST 删除规则,在删除完该结点后,我们需要直接用其孩子来替代该结点的位置:
44
平衡因子: -2 40
平衡因子: 0 78
平衡因子: 1 65
平衡因子: 0 85
平衡因子: 0 50
平衡因子: 0 72
平衡因子:0
删除完该结点后,通过向上查找,我们找到了 最小不平衡子树 : 44 44 44,接下来我们需要找到其最高的 孩子 和最高的 孙子:
44
平衡因子: -2
h = 4 40
平衡因子: 0
h = 1 78
平衡因子: 1
h = 3 65
平衡因子: 0
h = 2 85
平衡因子: 0
h = 1 50
平衡因子: 0
h = 1 72
平衡因子:0
h = 1
其最高的孩子为 右孩子 (R ),其最高的孙子为 右孩子 的 左子树 (L ),因此我们需要先对其 右孩子 进行一次 右单旋转 ,再对其做一次 左单旋转:
先对右子树: 78
做一次右单旋转
-> 44
平衡因子: -2
h = 4 40
平衡因子: 0
h = 1 65
平衡因子: -2
h = 3 50
平衡因子: 0
h = 1 78
平衡因子: 0
h = 2 72
平衡因子:0
h = 1 85
平衡因子: 0
h = 1 再对整棵树
做一次左单旋转
-> 65
平衡因子: 0
h = 3 44
平衡因子: 0
h = 2 40
平衡因子: 0
h = 1 50
平衡因子: 0
h = 1 78
平衡因子: 0
h = 2 72
平衡因子:0
h = 1 85
平衡因子: 0
h = 1
完成旋转后,该棵 BST 又重新恢复平衡,因此完成删除;
2.6 用例6:最小不平衡子树向上传导
在下面这棵 AVL树 中,我们需要删除结点 44 44 44:
33
平衡因子: 1 10
平衡因子: -1 44
平衡因子: -1 5
平衡因子: 1 20
平衡因子: -1 37
平衡因子: 1 78
平衡因子: 1 4
平衡因子: 1 8
平衡因子: 0 15
平衡因子: 1 25
平衡因子: 1 35
平衡因子: 0 NULL 50
平衡因子: 1 88
平衡因子: 0 1
平衡因子: 0 NULL 12
平衡因子: 0 NULL 23
平衡因子: 1 28
平衡因子: 0 48
平衡因子: 0 NULL 21
平衡因子: 0 NULL
由于该结点有两个孩子,根据 BST 的删除规则,我们在完成结点删除后,可以通过它的直接前驱或者直接后继来替代该结点的位置:
- 直接前驱:其左子树的最后侧孩子------ 37 37 37
- 直接后继:其右子树的最左侧孩子------ 48 48 48
旋转不同的孩子结点进行替代,可能会导致不同的结果,这里我们通过肉眼观察不难看出:
- 当采用直接后继时,失去平衡的为整棵树,因为前面已经探讨过,这里就不再介绍;
- 当采用直接前驱时,树的不平衡性会向上传导,因此,这里我们重点关注这种情况;
注意:这里是为了给大家介绍不平衡向上传导的情况,因此选择的是直接前驱;而在实际情况中,我们只需要根据自己的需求进行选择就好
接下我们通过结点 44 44 44 的直接前驱 37 37 37 来替代该结点的位置,由于进行替换的结点只有一个孩子,因此该结点的位置由其孩子进行替代:
33
平衡因子: 1 10
平衡因子: -1 37
平衡因子: -2 5
平衡因子: 1 20
平衡因子: -1 35
平衡因子: 0 78
平衡因子: 1 4
平衡因子: 1 8
平衡因子: 0 15
平衡因子: 1 25
平衡因子: 1 50
平衡因子: 1 88
平衡因子: 0 1
平衡因子: 0 NULL 12
平衡因子: 0 NULL 23
平衡因子: 1 28
平衡因子: 0 48
平衡因子: 0 NULL 21
平衡因子: 0 NULL
通过向上查找,我们找到了 最小不平衡子树 ,其根结点为 37 37 37 ,因此我们需要找到其最高的 孩子 和最高的 孙子:
33
平衡因子: 1
h = 6 10
平衡因子: -1
h = 5 37
平衡因子: -2
h = 4 5
平衡因子: 1
h = 3 20
平衡因子: -1
h = 4 35
平衡因子: 0
h = 1 78
平衡因子: 1
h = 3 4
平衡因子: 1
h = 2 8
平衡因子: 0
h = 1 15
平衡因子: 1
h = 2 25
平衡因子: 1
h = 3 50
平衡因子: 1
h = 2 88
平衡因子: 0
h = 1 1
平衡因子: 0
h = 1 NULL 12
平衡因子: 0
h = 1 NULL 23
平衡因子: 1
h = 2 28
平衡因子: 0
h = 1 48
平衡因子: 0
h = 1 NULL 21
平衡因子: 0
h = 1 NULL
其最高的孩子为 右孩子 (R ),其最高的孙子为其 右孩子 的 左子树 (L ),因此我们需要对 最小不平衡子树 的 右孩子 进行一次 右单旋转:
33
平衡因子: 1
h = 6 10
平衡因子: -1
h = 5 37
平衡因子: -2
h = 4 5
平衡因子: 1
h = 3 20
平衡因子: -1
h = 4 35
平衡因子: 0
h = 1 50
平衡因子: -1
h = 3 48
平衡因子: 0
h = 1 78
平衡因子: -1
h = 2 4
平衡因子: 1
h = 2 8
平衡因子: 0
h = 1 15
平衡因子: 1
h = 2 25
平衡因子: 1
h = 3 88
平衡因子: 0
h = 1 NULL 1
平衡因子: 0
h = 1 NULL 12
平衡因子: 0
h = 1 NULL 23
平衡因子: 1
h = 2 28
平衡因子: 0
h = 1 21
平衡因子: 0
h = 1 NULL
再对该 最小不平衡子树 进行一次 左单旋转:
33
平衡因子: 2
h = 6 10
平衡因子: -1
h = 5 50
平衡因子: 0
h = 3 5
平衡因子: 1
h = 3 20
平衡因子: -1
h = 4 37
平衡因子: 0
h = 2 35
平衡因子: 0
h = 1 48
平衡因子: 0
h = 1 78
平衡因子: -1
h = 2 4
平衡因子: 1
h = 2 8
平衡因子: 0
h = 1 15
平衡因子: 1
h = 2 25
平衡因子: 1
h = 3 88
平衡因子: 0
h = 1 NULL 1
平衡因子: 0
h = 1 NULL 12
平衡因子: 0
h = 1 NULL 23
平衡因子: 1
h = 2 28
平衡因子: 0
h = 1 21
平衡因子: 0
h = 1 NULL
完成平衡调整后,我们继续向上查找,发现此时的 最小不平衡子树 为 33 33 33 ,因此我们需要找到其最高的 孩子 和最高的 孙子:
33
平衡因子: 2
h = 6 10
平衡因子: -1
h = 5 50
平衡因子: 0
h = 3 5
平衡因子: 1
h = 3 20
平衡因子: -1
h = 4 37
平衡因子: 0
h = 2 35
平衡因子: 0
h = 1 48
平衡因子: 0
h = 1 78
平衡因子: -1
h = 2 4
平衡因子: 1
h = 2 8
平衡因子: 0
h = 1 15
平衡因子: 1
h = 2 25
平衡因子: 1
h = 3 88
平衡因子: 0
h = 1 NULL 1
平衡因子: 0
h = 1 NULL 12
平衡因子: 0
h = 1 NULL 23
平衡因子: 1
h = 2 28
平衡因子: 0
h = 1 21
平衡因子: 0
h = 1 NULL
其最高的孩子为其 左孩子 (L ),其最高的孙子为 左孩子 的 左子树 (L ),因此我们需要先对其 左孩子 进行一次左单旋转:
33
平衡因子: 2
h = 6 20
平衡因子: 1
h = 5 10
平衡因子: 1
h = 4 50
平衡因子: 0
h = 3 5
平衡因子: 1
h = 3 37
平衡因子: 0
h = 2 35
平衡因子: 0
h = 1 48
平衡因子: 0
h = 1 78
平衡因子: -1
h = 2 4
平衡因子: 1
h = 2 8
平衡因子: 0
h = 1 15
平衡因子: 1
h = 2 25
平衡因子: 1
h = 3 88
平衡因子: 0
h = 1 NULL 1
平衡因子: 0
h = 1 NULL 12
平衡因子: 0
h = 1 NULL 23
平衡因子: 1
h = 2 28
平衡因子: 0
h = 1 21
平衡因子: 0
h = 1 NULL
再对该 最小不平衡子树 进行一次 右单旋转:
20
平衡因子: 0
h = 5 10
平衡因子: 1
h = 4 33
平衡因子: 2
h = 4 25
平衡因子: 1
h = 3 50
平衡因子: 0
h = 3 5
平衡因子: 1
h = 3 37
平衡因子: 0
h = 2 35
平衡因子: 0
h = 1 48
平衡因子: 0
h = 1 78
平衡因子: -1
h = 2 4
平衡因子: 1
h = 2 8
平衡因子: 0
h = 1 15
平衡因子: 1
h = 2 88
平衡因子: 0
h = 1 NULL 1
平衡因子: 0
h = 1 NULL 12
平衡因子: 0
h = 1 NULL 23
平衡因子: 1
h = 2 28
平衡因子: 0
h = 1 21
平衡因子: 0
h = 1 NULL
经过这一的平衡旋转后,整棵树已经恢复了平衡,因此结束删除;
结语
今天的内容到这里就结束了,通过今天的学习,我们系统性地掌握了AVL树删除操作的核心机制。
下面我们一起回顾以下本文的重要知识点:
核心操作步骤:
- 按照BST规则进行节点删除
- 向上查找第一个最小不平衡子树
- 根据"孙子节点"位置判断旋转类型(LL/LR/RR/RL)
- 执行对应的单旋或双旋操作
- 检查不平衡是否向上传导,必要时重复调整
关键技巧:
-
通过"最高孩子→最高孙子"的路径判断旋转类型
-
双旋操作需要先对子节点旋转,再对根节点旋转
-
删除操作可能引发连锁不平衡,需要持续向上调整
实际应用:
- 通过6个典型用例,我们完整覆盖了各种删除场景,特别是用例6展示的不平衡向上传导情况,帮助大家深入理解AVL树的自平衡特性。
掌握了AVL树的插入和删除操作后,相信大家对平衡二叉搜索树有了更深刻的理解。这些基础知识对于学习更高级的数据结构(如红黑树、B树等)至关重要。
如果本文对你有帮助,欢迎点赞⭐、收藏📁、关注✅,你的支持是我持续创作的最大动力!
有任何问题或想法,欢迎在评论区留言💬,我们一起交流讨论!
也可以转发分享🔗给更多需要的小伙伴,共同进步~
接下来我们将继续深入数据结构与算法的精彩世界,敬请期待!