Fix the figures of binary tree.
Replace null with None.
|
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$** 。
|
||||
|
||||

|
||||

|
||||
|
||||
**映射公式的作用相当于链表中的指针**。如果我们将节点按照层序遍历的顺序存储在一个数组中,那么对于数组中的任意节点,我们都可以通过映射公式来访问其子节点。
|
||||
|
||||
## 表示任意二叉树
|
||||
|
||||
然而,完美二叉树只是一个特例。在二叉树的中间层,通常存在许多 $\text{null}$ ,而层序遍历序列并不包含这些 $\text{null}$ 。我们无法仅凭该序列来推测 $\text{null}$ 的数量和分布位置,**这意味着存在多种二叉树结构都符合该层序遍历序列**。显然在这种情况下,上述的数组表示方法已经失效。
|
||||
然而,完美二叉树只是一个特例。在二叉树的中间层,通常存在许多 $\text{None}$ ,而层序遍历序列并不包含这些 $\text{None}$ 。我们无法仅凭该序列来推测 $\text{None}$ 的数量和分布位置,**这意味着存在多种二叉树结构都符合该层序遍历序列**。显然在这种情况下,上述的数组表示方法已经失效。
|
||||
|
||||

|
||||

|
||||
|
||||
为了解决此问题,**我们可以考虑在层序遍历序列中显式地写出所有 $\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];
|
||||
```
|
||||
|
||||

|
||||

|
||||
|
||||
## 优势与局限性
|
||||
|
||||
@@ -122,8 +122,8 @@
|
||||
|
||||
- 数组存储需要连续内存空间,因此不适合存储数据量过大的树。
|
||||
- 增删节点需要通过数组插入与删除操作实现,效率较低;
|
||||
- 当二叉树中存在大量 $\text{null}$ 时,数组中包含的节点数据比重较低,空间利用率较低。
|
||||
- 当二叉树中存在大量 $\text{None}$ 时,数组中包含的节点数据比重较低,空间利用率较低。
|
||||
|
||||
**完全二叉树非常适合使用数组来表示**。回顾完全二叉树的定义,$\text{null}$ 只出现在最底层且靠右的位置,**这意味着所有 $\text{null}$ 一定出现在层序遍历序列的末尾**。因此,在使用数组表示完全二叉树时,可以省略存储所有 $\text{null}$ 。
|
||||
**完全二叉树非常适合使用数组来表示**。回顾完全二叉树的定义,$\text{None}$ 只出现在最底层且靠右的位置,**这意味着所有 $\text{None}$ 一定出现在层序遍历序列的末尾**。因此,在使用数组表示完全二叉树时,可以省略存储所有 $\text{None}$ 。
|
||||
|
||||

|
||||

|
||||
|
||||
|
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)$ ;
|
||||
|
||||

|
||||

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