Fix the figures of binary tree.
Replace null with None.
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 77 KiB After Width: | Height: | Size: 77 KiB |
|
@ -166,7 +166,7 @@
|
|||
|
||||
!!! question "尾节点指向什么?"
|
||||
|
||||
我们将链表的最后一个节点称为「尾节点」,其指向的是“空”,在 Java, C++, Python 中分别记为 $\text{null}$ , $\text{nullptr}$ , $\text{None}$ 。在不引起歧义的前提下,本书都使用 $\text{null}$ 来表示空。
|
||||
我们将链表的最后一个节点称为「尾节点」,其指向的是“空”,在 Java, C++, Python 中分别记为 $\text{null}$ , $\text{nullptr}$ , $\text{None}$ 。在不引起歧义的前提下,本书都使用 $\text{None}$ 来表示空。
|
||||
|
||||
!!! question "如何称呼链表?"
|
||||
|
||||
|
@ -647,7 +647,7 @@
|
|||
|
||||
## 常见链表类型
|
||||
|
||||
**单向链表**。即上述介绍的普通链表。单向链表的节点包含值和指向下一节点的指针(引用)两项数据。我们将首个节点称为头节点,将最后一个节点成为尾节点,尾节点指向 $\text{null}$ 。
|
||||
**单向链表**。即上述介绍的普通链表。单向链表的节点包含值和指向下一节点的指针(引用)两项数据。我们将首个节点称为头节点,将最后一个节点成为尾节点,尾节点指向空 $\text{None}$ 。
|
||||
|
||||
**环形链表**。如果我们令单向链表的尾节点指向头节点(即首尾相接),则得到一个环形链表。在环形链表中,任意节点都可以视作头节点。
|
||||
|
||||
|
|
|
@ -6,15 +6,12 @@
|
|||
|
||||
## 行文风格约定
|
||||
|
||||
标题后标注 `*` 的是选读章节,内容相对困难。如果你的时间有限,建议可以先跳过。
|
||||
|
||||
文章中的重要名词会用 `「 」` 括号标注,例如 `「数组 Array」` 。请务必记住这些名词,包括英文翻译,以便后续阅读文献时使用。
|
||||
|
||||
**加粗的文字** 表示重点内容或总结性语句,这类文字值得特别关注。
|
||||
|
||||
专有名词和有特指含义的词句会使用 `“双引号”` 标注,以避免歧义。
|
||||
|
||||
本书部分放弃了编程语言的注释规范,以换取更加紧凑的内容排版。注释主要分为三种类型:标题注释、内容注释、多行注释。
|
||||
- 标题后标注 `*` 的是选读章节,内容相对困难。如果你的时间有限,建议可以先跳过。
|
||||
- 文章中的重要名词会用 `「 」` 括号标注,例如 `「数组 Array」` 。请务必记住这些名词,包括英文翻译,以便后续阅读文献时使用。
|
||||
- **加粗的文字** 表示重点内容或总结性语句,这类文字值得特别关注。
|
||||
- 专有名词和有特指含义的词句会使用 `“双引号”` 标注,以避免歧义。
|
||||
- 涉及到编程语言之间不一致的名词,本书均以 Python 为准,例如使用 $\text{None}$ 来表示“空”。
|
||||
- 本书部分放弃了编程语言的注释规范,以换取更加紧凑的内容排版。注释主要分为三种类型:标题注释、内容注释、多行注释。
|
||||
|
||||
=== "Java"
|
||||
|
||||
|
|
After Width: | Height: | Size: 86 KiB |
After Width: | Height: | Size: 67 KiB |
After Width: | Height: | Size: 75 KiB |
After Width: | Height: | Size: 66 KiB |
|
@ -10,17 +10,17 @@
|
|||
|
||||
根据层序遍历的特性,我们可以推导出父节点索引与子节点索引之间的“映射公式”:**若节点的索引为 $i$ ,则该节点的左子节点索引为 $2i + 1$ ,右子节点索引为 $2i + 2$** 。
|
||||
|
||||
![完美二叉树的数组表示](binary_tree.assets/array_representation_mapping.png)
|
||||
![完美二叉树的数组表示](array_representation_of_tree.assets/array_representation_binary_tree.png)
|
||||
|
||||
**映射公式的作用相当于链表中的指针**。如果我们将节点按照层序遍历的顺序存储在一个数组中,那么对于数组中的任意节点,我们都可以通过映射公式来访问其子节点。
|
||||
|
||||
## 表示任意二叉树
|
||||
|
||||
然而,完美二叉树只是一个特例。在二叉树的中间层,通常存在许多 $\text{null}$ ,而层序遍历序列并不包含这些 $\text{null}$ 。我们无法仅凭该序列来推测 $\text{null}$ 的数量和分布位置,**这意味着存在多种二叉树结构都符合该层序遍历序列**。显然在这种情况下,上述的数组表示方法已经失效。
|
||||
然而,完美二叉树只是一个特例。在二叉树的中间层,通常存在许多 $\text{None}$ ,而层序遍历序列并不包含这些 $\text{None}$ 。我们无法仅凭该序列来推测 $\text{None}$ 的数量和分布位置,**这意味着存在多种二叉树结构都符合该层序遍历序列**。显然在这种情况下,上述的数组表示方法已经失效。
|
||||
|
||||
![层序遍历序列对应多种二叉树可能性](binary_tree.assets/array_representation_without_empty.png)
|
||||
![层序遍历序列对应多种二叉树可能性](array_representation_of_tree.assets/array_representation_without_empty.png)
|
||||
|
||||
为了解决此问题,**我们可以考虑在层序遍历序列中显式地写出所有 $\text{null}$**。如下图所示,这样处理后,层序遍历序列就可以唯一表示二叉树了。
|
||||
为了解决此问题,**我们可以考虑在层序遍历序列中显式地写出所有 $\text{None}$**。如下图所示,这样处理后,层序遍历序列就可以唯一表示二叉树了。
|
||||
|
||||
=== "Java"
|
||||
|
||||
|
@ -108,7 +108,7 @@
|
|||
List<int?> tree = [1, 2, 3, 4, null, 6, 7, 8, 9, null, null, 12, null, null, 15];
|
||||
```
|
||||
|
||||
![任意类型二叉树的数组表示](binary_tree.assets/array_representation_with_empty.png)
|
||||
![任意类型二叉树的数组表示](array_representation_of_tree.assets/array_representation_with_empty.png)
|
||||
|
||||
## 优势与局限性
|
||||
|
||||
|
@ -122,8 +122,8 @@
|
|||
|
||||
- 数组存储需要连续内存空间,因此不适合存储数据量过大的树。
|
||||
- 增删节点需要通过数组插入与删除操作实现,效率较低;
|
||||
- 当二叉树中存在大量 $\text{null}$ 时,数组中包含的节点数据比重较低,空间利用率较低。
|
||||
- 当二叉树中存在大量 $\text{None}$ 时,数组中包含的节点数据比重较低,空间利用率较低。
|
||||
|
||||
**完全二叉树非常适合使用数组来表示**。回顾完全二叉树的定义,$\text{null}$ 只出现在最底层且靠右的位置,**这意味着所有 $\text{null}$ 一定出现在层序遍历序列的末尾**。因此,在使用数组表示完全二叉树时,可以省略存储所有 $\text{null}$ 。
|
||||
**完全二叉树非常适合使用数组来表示**。回顾完全二叉树的定义,$\text{None}$ 只出现在最底层且靠右的位置,**这意味着所有 $\text{None}$ 一定出现在层序遍历序列的末尾**。因此,在使用数组表示完全二叉树时,可以省略存储所有 $\text{None}$ 。
|
||||
|
||||
![完全二叉树的数组表示](binary_tree.assets/array_representation_complete_binary_tree.png)
|
||||
![完全二叉树的数组表示](array_representation_of_tree.assets/array_representation_complete_binary_tree.png)
|
||||
|
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 86 KiB |
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 86 KiB |
|
@ -101,8 +101,8 @@
|
|||
|
||||
给定一个待插入元素 `num` ,为了保持二叉搜索树“左子树 < 根节点 < 右子树”的性质,插入操作分为两步:
|
||||
|
||||
1. **查找插入位置**:与查找操作相似,从根节点出发,根据当前节点值和 `num` 的大小关系循环向下搜索,直到越过叶节点(遍历至 $\text{null}$ )时跳出循环;
|
||||
2. **在该位置插入节点**:初始化节点 `num` ,将该节点置于 $\text{null}$ 的位置;
|
||||
1. **查找插入位置**:与查找操作相似,从根节点出发,根据当前节点值和 `num` 的大小关系循环向下搜索,直到越过叶节点(遍历至 $\text{None}$ )时跳出循环;
|
||||
2. **在该位置插入节点**:初始化节点 `num` ,将该节点置于 $\text{None}$ 的位置;
|
||||
|
||||
二叉搜索树不允许存在重复节点,否则将违反其定义。因此,若待插入节点在树中已存在,则不执行插入,直接返回。
|
||||
|
||||
|
@ -174,7 +174,7 @@
|
|||
[class]{BinarySearchTree}-[func]{insert}
|
||||
```
|
||||
|
||||
为了插入节点,我们需要利用辅助节点 `pre` 保存上一轮循环的节点,这样在遍历至 $\text{null}$ 时,我们可以获取到其父节点,从而完成节点插入操作。
|
||||
为了插入节点,我们需要利用辅助节点 `pre` 保存上一轮循环的节点,这样在遍历至 $\text{None}$ 时,我们可以获取到其父节点,从而完成节点插入操作。
|
||||
|
||||
与查找节点相同,插入节点使用 $O(\log n)$ 时间。
|
||||
|
||||
|
|
Before Width: | Height: | Size: 71 KiB |
Before Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 59 KiB |
|
@ -166,7 +166,7 @@
|
|||
二叉树涉及的术语较多,建议尽量理解并记住。
|
||||
|
||||
- 「根节点 Root Node」:位于二叉树顶层的节点,没有父节点;
|
||||
- 「叶节点 Leaf Node」:没有子节点的节点,其两个指针均指向 $\text{null}$ ;
|
||||
- 「叶节点 Leaf Node」:没有子节点的节点,其两个指针均指向 $\text{None}$ ;
|
||||
- 节点的「层 Level」:从顶至底递增,根节点所在层为 1 ;
|
||||
- 节点的「度 Degree」:节点的子节点的数量。在二叉树中,度的范围是 0, 1, 2 ;
|
||||
- 「边 Edge」:连接两个节点的线段,即节点指针;
|
||||
|
@ -527,7 +527,7 @@
|
|||
- 完美二叉树是理想情况,可以充分发挥二叉树“分治”的优势;
|
||||
- 链表则是另一个极端,各项操作都变为线性操作,时间复杂度退化至 $O(n)$ ;
|
||||
|
||||
![二叉树的最佳与最差结构](binary_tree.assets/binary_tree_corner_cases.png)
|
||||
![二叉树的最佳与最差结构](binary_tree.assets/binary_tree_best_worst_cases.png)
|
||||
|
||||
如下表所示,在最佳和最差结构下,二叉树的叶节点数量、节点总数、高度等达到极大或极小值。
|
||||
|
||||
|
|