mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-11 19:30:59 +00:00
build
This commit is contained in:
@@ -10,10 +10,14 @@ comments: true
|
||||
|
||||

|
||||
|
||||
<p align="center"> Fig. AVL 树在删除结点后发生退化 </p>
|
||||
|
||||
再比如,在以下完美二叉树中插入两个结点后,树严重向左偏斜,查找操作的时间复杂度也随之发生劣化。
|
||||
|
||||

|
||||
|
||||
<p align="center"> Fig. AVL 树在插入结点后发生退化 </p>
|
||||
|
||||
G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorithm for the organization of information" 中提出了「AVL 树」。**论文中描述了一系列操作,使得在不断添加与删除结点后,AVL 树仍然不会发生退化**,进而使得各种操作的时间复杂度均能保持在 $O(\log n)$ 级别。
|
||||
|
||||
换言之,在频繁增删查改的使用场景中,AVL 树可始终保持很高的数据增删查改效率,具有很好的应用价值。
|
||||
@@ -470,6 +474,8 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影
|
||||
|
||||

|
||||
|
||||
<p align="center"> Fig. 有 grandChild 的右旋操作 </p>
|
||||
|
||||
“向右旋转”是一种形象化的说法,实际需要通过修改结点指针实现,代码如下所示。
|
||||
|
||||
=== "Java"
|
||||
@@ -646,10 +652,14 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影
|
||||
|
||||

|
||||
|
||||
<p align="center"> Fig. 左旋操作 </p>
|
||||
|
||||
同理,若结点 `child` 本身有左子结点(记为 `grandChild` ),则需要在「左旋」中添加一步:将 `grandChild` 作为 `node` 的右子结点。
|
||||
|
||||

|
||||
|
||||
<p align="center"> Fig. 有 grandChild 的左旋操作 </p>
|
||||
|
||||
观察发现,**「左旋」和「右旋」操作是镜像对称的,两者对应解决的两种失衡情况也是对称的**。根据对称性,我们可以很方便地从「右旋」推导出「左旋」。具体地,只需将「右旋」代码中的把所有的 `left` 替换为 `right` 、所有的 `right` 替换为 `left` ,即可得到「左旋」代码。
|
||||
|
||||
=== "Java"
|
||||
@@ -826,18 +836,24 @@ AVL 树的独特之处在于「旋转 Rotation」的操作,其可 **在不影
|
||||
|
||||

|
||||
|
||||
<p align="center"> Fig. 先左旋后右旋 </p>
|
||||
|
||||
### Case 4 - 先右后左
|
||||
|
||||
同理,取以上失衡二叉树的镜像,则需要「先右旋后左旋」,即先对 `child` 执行「右旋」,然后对 `node` 执行「左旋」。
|
||||
|
||||

|
||||
|
||||
<p align="center"> Fig. 先右旋后左旋 </p>
|
||||
|
||||
### 旋转的选择
|
||||
|
||||
下图描述的四种失衡情况与上述 Cases 逐个对应,分别需采用 **右旋、左旋、先右后左、先左后右** 的旋转操作。
|
||||
|
||||

|
||||
|
||||
<p align="center"> Fig. AVL 树的四种旋转情况 </p>
|
||||
|
||||
具体地,在代码中使用 **失衡结点的平衡因子、较高一侧子结点的平衡因子** 来确定失衡结点属于上图中的哪种情况。
|
||||
|
||||
<div class="center-table" markdown>
|
||||
|
||||
Reference in New Issue
Block a user