mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-11 06:56:06 +00:00
build
This commit is contained in:
@@ -14,7 +14,7 @@ comments: true
|
||||
|
||||
根据层序遍历的特性,我们可以推导出父节点索引与子节点索引之间的“映射公式”:**若节点的索引为 $i$ ,则该节点的左子节点索引为 $2i + 1$ ,右子节点索引为 $2i + 2$** 。图 7-12 展示了各个节点索引之间的映射关系。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-12 完美二叉树的数组表示 </p>
|
||||
|
||||
@@ -26,7 +26,7 @@ comments: true
|
||||
|
||||
如图 7-13 所示,给定一个非完美二叉树,上述的数组表示方法已经失效。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-13 层序遍历序列对应多种二叉树可能性 </p>
|
||||
|
||||
@@ -126,7 +126,7 @@ comments: true
|
||||
|
||||
```
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-14 任意类型二叉树的数组表示 </p>
|
||||
|
||||
@@ -134,7 +134,7 @@ comments: true
|
||||
|
||||
这意味着使用数组表示完全二叉树时,可以省略存储所有 $\text{None}$ ,非常方便。图 7-15 给出了一个例子。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-15 完全二叉树的数组表示 </p>
|
||||
|
||||
|
||||
@@ -8,13 +8,13 @@ comments: true
|
||||
|
||||
如图 7-24 所示,经过两次删除节点操作,这个二叉搜索树便会退化为链表。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-24 AVL 树在删除节点后发生退化 </p>
|
||||
|
||||
再例如,在图 7-25 的完美二叉树中插入两个节点后,树将严重向左倾斜,查找操作的时间复杂度也随之恶化。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-25 AVL 树在插入节点后发生退化 </p>
|
||||
|
||||
@@ -610,22 +610,22 @@ AVL 树的特点在于“旋转”操作,它能够在不影响二叉树的中
|
||||
如图 7-26 所示,节点下方为平衡因子。从底至顶看,二叉树中首个失衡节点是“节点 3”。我们关注以该失衡节点为根节点的子树,将该节点记为 `node` ,其左子节点记为 `child` ,执行“右旋”操作。完成右旋后,子树已经恢复平衡,并且仍然保持二叉搜索树的特性。
|
||||
|
||||
=== "<1>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<2>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<3>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<4>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-26 右旋操作步骤 </p>
|
||||
|
||||
如图 7-27 所示,当节点 `child` 有右子节点(记为 `grandChild` )时,需要在右旋中添加一步:将 `grandChild` 作为 `node` 的左子节点。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-27 有 grandChild 的右旋操作 </p>
|
||||
|
||||
@@ -856,13 +856,13 @@ AVL 树的特点在于“旋转”操作,它能够在不影响二叉树的中
|
||||
|
||||
相应的,如果考虑上述失衡二叉树的“镜像”,则需要执行图 7-28 所示的“左旋”操作。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-28 左旋操作 </p>
|
||||
|
||||
同理,如图 7-29 所示,当节点 `child` 有左子节点(记为 `grandChild` )时,需要在左旋中添加一步:将 `grandChild` 作为 `node` 的右子节点。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-29 有 grandChild 的左旋操作 </p>
|
||||
|
||||
@@ -1093,7 +1093,7 @@ AVL 树的特点在于“旋转”操作,它能够在不影响二叉树的中
|
||||
|
||||
对于图 7-30 中的失衡节点 3 ,仅使用左旋或右旋都无法使子树恢复平衡。此时需要先对 `child` 执行“左旋”,再对 `node` 执行“右旋”。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-30 先左旋后右旋 </p>
|
||||
|
||||
@@ -1101,7 +1101,7 @@ AVL 树的特点在于“旋转”操作,它能够在不影响二叉树的中
|
||||
|
||||
如图 7-31 所示,对于上述失衡二叉树的镜像情况,需要先对 `child` 执行“右旋”,然后对 `node` 执行“左旋”。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-31 先右旋后左旋 </p>
|
||||
|
||||
@@ -1109,7 +1109,7 @@ AVL 树的特点在于“旋转”操作,它能够在不影响二叉树的中
|
||||
|
||||
图 7-32 展示的四种失衡情况与上述案例逐个对应,分别需要采用右旋、左旋、先右后左、先左后右的旋转操作。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-32 AVL 树的四种旋转情况 </p>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ comments: true
|
||||
1. 对于根节点,左子树中所有节点的值 $<$ 根节点的值 $<$ 右子树中所有节点的值。
|
||||
2. 任意节点的左、右子树也是二叉搜索树,即同样满足条件 `1.` 。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-16 二叉搜索树 </p>
|
||||
|
||||
@@ -26,16 +26,16 @@ comments: true
|
||||
- 若 `cur.val = num` ,说明找到目标节点,跳出循环并返回该节点。
|
||||
|
||||
=== "<1>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<2>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<3>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<4>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-17 二叉搜索树查找节点示例 </p>
|
||||
|
||||
@@ -325,7 +325,7 @@ comments: true
|
||||
1. **查找插入位置**:与查找操作相似,从根节点出发,根据当前节点值和 `num` 的大小关系循环向下搜索,直到越过叶节点(遍历至 $\text{None}$ )时跳出循环。
|
||||
2. **在该位置插入节点**:初始化节点 `num` ,将该节点置于 $\text{None}$ 的位置。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-18 在二叉搜索树中插入节点 </p>
|
||||
|
||||
@@ -753,13 +753,13 @@ comments: true
|
||||
|
||||
如图 7-19 所示,当待删除节点的度为 $0$ 时,表示该节点是叶节点,可以直接删除。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-19 在二叉搜索树中删除节点(度为 0 ) </p>
|
||||
|
||||
如图 7-20 所示,当待删除节点的度为 $1$ 时,将待删除节点替换为其子节点即可。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-20 在二叉搜索树中删除节点(度为 1 ) </p>
|
||||
|
||||
@@ -771,16 +771,16 @@ comments: true
|
||||
2. 将 `tmp` 的值覆盖待删除节点的值,并在树中递归删除节点 `tmp` 。
|
||||
|
||||
=== "<1>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<2>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<3>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<4>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-21 在二叉搜索树中删除节点(度为 2 ) </p>
|
||||
|
||||
@@ -1464,7 +1464,7 @@ comments: true
|
||||
|
||||
利用中序遍历升序的性质,我们在二叉搜索树中获取有序数据仅需 $O(n)$ 时间,无须进行额外的排序操作,非常高效。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-22 二叉搜索树的中序遍历序列 </p>
|
||||
|
||||
@@ -1488,7 +1488,7 @@ comments: true
|
||||
|
||||
然而,如果我们在二叉搜索树中不断地插入和删除节点,可能导致二叉树退化为图 7-23 所示的链表,这时各种操作的时间复杂度也会退化为 $O(n)$ 。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-23 二叉搜索树的退化 </p>
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ comments: true
|
||||
|
||||
**在二叉树中,除叶节点外,其他所有节点都包含子节点和非空子树**。如图 7-1 所示,如果将“节点 2”视为父节点,则其左子节点和右子节点分别是“节点 4”和“节点 5”,左子树是“节点 4 及其以下节点形成的树”,右子树是“节点 5 及其以下节点形成的树”。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-1 父节点、子节点、子树 </p>
|
||||
|
||||
@@ -208,7 +208,7 @@ comments: true
|
||||
- 节点的「深度 depth」:从根节点到该节点所经过的边的数量。
|
||||
- 节点的「高度 height」:从距离该节点最远的叶节点到该节点所经过的边的数量。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-2 二叉树的常用术语 </p>
|
||||
|
||||
@@ -416,7 +416,7 @@ comments: true
|
||||
|
||||
与链表类似,在二叉树中插入与删除节点可以通过修改指针来实现。图 7-3 给出了一个示例。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-3 在二叉树中插入与删除节点 </p>
|
||||
|
||||
@@ -569,7 +569,7 @@ comments: true
|
||||
|
||||
请注意,在中文社区中,完美二叉树常被称为「满二叉树」。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-4 完美二叉树 </p>
|
||||
|
||||
@@ -577,7 +577,7 @@ comments: true
|
||||
|
||||
如图 7-5 所示,「完全二叉树 complete binary tree」只有最底层的节点未被填满,且最底层节点尽量靠左填充。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-5 完全二叉树 </p>
|
||||
|
||||
@@ -585,7 +585,7 @@ comments: true
|
||||
|
||||
如图 7-6 所示,「完满二叉树 full binary tree」除了叶节点之外,其余所有节点都有两个子节点。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-6 完满二叉树 </p>
|
||||
|
||||
@@ -593,7 +593,7 @@ comments: true
|
||||
|
||||
如图 7-7 所示,「平衡二叉树 balanced binary tree」中任意节点的左子树和右子树的高度之差的绝对值不超过 1 。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-7 平衡二叉树 </p>
|
||||
|
||||
@@ -604,7 +604,7 @@ comments: true
|
||||
- 完美二叉树是理想情况,可以充分发挥二叉树“分治”的优势。
|
||||
- 链表则是另一个极端,各项操作都变为线性操作,时间复杂度退化至 $O(n)$ 。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-8 二叉树的最佳与最差结构 </p>
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ comments: true
|
||||
|
||||
层序遍历本质上属于「广度优先遍历 breadth-first traversal」,它体现了一种“一圈一圈向外扩展”的逐层遍历方式。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-9 二叉树的层序遍历 </p>
|
||||
|
||||
@@ -335,7 +335,7 @@ comments: true
|
||||
|
||||
图 7-10 展示了对二叉树进行深度优先遍历的工作原理。**深度优先遍历就像是绕着整个二叉树的外围“走”一圈**,在每个节点都会遇到三个位置,分别对应前序遍历、中序遍历和后序遍历。
|
||||
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-10 二叉搜索树的前、中、后序遍历 </p>
|
||||
|
||||
@@ -764,37 +764,37 @@ comments: true
|
||||
2. “归”表示函数返回,代表当前节点已经访问完毕。
|
||||
|
||||
=== "<1>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<2>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<3>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<4>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<5>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<6>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<7>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<8>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<9>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<10>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
=== "<11>"
|
||||

|
||||
{ class="animation-figure" }
|
||||
|
||||
<p align="center"> 图 7-11 前序遍历的递归过程 </p>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ icon: material/graph-outline
|
||||
|
||||
<div class="center-table" markdown>
|
||||
|
||||
{ width="600" }
|
||||
{ class="cover-image" }
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user