Fix the figures of binary tree.

Replace null with None.
This commit is contained in:
krahets 2023-06-17 00:45:41 +08:00
parent 73372ad35a
commit b6b03ef84b
23 changed files with 21 additions and 24 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 77 KiB

View file

@ -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}$ 。
**环形链表**。如果我们令单向链表的尾节点指向头节点(即首尾相接),则得到一个环形链表。在环形链表中,任意节点都可以视作头节点。

View file

@ -6,15 +6,12 @@
## 行文风格约定
标题后标注 `*` 的是选读章节,内容相对困难。如果你的时间有限,建议可以先跳过。
文章中的重要名词会用 `「 」` 括号标注,例如 `「数组 Array」` 。请务必记住这些名词,包括英文翻译,以便后续阅读文献时使用。
**加粗的文字** 表示重点内容或总结性语句,这类文字值得特别关注。
专有名词和有特指含义的词句会使用 `“双引号”` 标注,以避免歧义。
本书部分放弃了编程语言的注释规范,以换取更加紧凑的内容排版。注释主要分为三种类型:标题注释、内容注释、多行注释。
- 标题后标注 `*` 的是选读章节,内容相对困难。如果你的时间有限,建议可以先跳过。
- 文章中的重要名词会用 `「 」` 括号标注,例如 `「数组 Array」` 。请务必记住这些名词,包括英文翻译,以便后续阅读文献时使用。
- **加粗的文字** 表示重点内容或总结性语句,这类文字值得特别关注。
- 专有名词和有特指含义的词句会使用 `“双引号”` 标注,以避免歧义。
- 涉及到编程语言之间不一致的名词,本书均以 Python 为准,例如使用 $\text{None}$ 来表示“空”。
- 本书部分放弃了编程语言的注释规范,以换取更加紧凑的内容排版。注释主要分为三种类型:标题注释、内容注释、多行注释。
=== "Java"

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View file

@ -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)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 86 KiB

View file

@ -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)$ 时间。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View file

@ -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)
如下表所示,在最佳和最差结构下,二叉树的叶节点数量、节点总数、高度等达到极大或极小值。