Skip to content

Commit

Permalink
Revise base on the manuscript of the first edition
Browse files Browse the repository at this point in the history
  • Loading branch information
krahets committed Dec 28, 2023
1 parent 8123450 commit b52a840
Show file tree
Hide file tree
Showing 7 changed files with 19 additions and 19 deletions.
6 changes: 3 additions & 3 deletions docs/chapter_array_and_linkedlist/summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@

!!! question "为什么数组要求相同类型的元素,而在链表中却没有强调同类型呢?"

链表由节点组成,节点之间通过引用(指针)连接,各个节点可以存储不同类型的数据,例如 intdoublestringobject 等。
链表由节点组成,节点之间通过引用(指针)连接,各个节点可以存储不同类型的数据,例如 `int`、`double`、`string`、`object` 等。

相对地,数组元素则必须是相同类型的,这样才能通过计算偏移量来获取对应元素位置。例如,数组同时包含 int 和 long 两种类型,单个元素分别占用 4 字节 和 8 字节 ,此时就不能用以下公式计算偏移量了,因为数组中包含了两种“元素长度”。
相对地,数组元素则必须是相同类型的,这样才能通过计算偏移量来获取对应元素位置。例如,数组同时包含 `int``long` 两种类型,单个元素分别占用 4 字节 和 8 字节 ,此时就不能用以下公式计算偏移量了,因为数组中包含了两种“元素长度”。

```shell
# 元素内存地址 = 数组内存地址 + 元素长度 * 元素索引
Expand All @@ -45,7 +45,7 @@

该示意图只是定性表示,定量表示需要根据具体情况进行分析。

- 不同类型的节点值占用的空间是不同的,比如 intlongdouble 和实例对象等。
- 不同类型的节点值占用的空间是不同的,比如 `int`、`long`、`double` 和实例对象等。
- 指针变量占用的内存空间大小根据所使用的操作系统及编译环境而定,大多为 8 字节或 4 字节。

!!! question "在列表末尾添加元素是否时时刻刻都为 $O(1)$ ?"
Expand Down
4 changes: 2 additions & 2 deletions docs/chapter_data_structure/summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@

!!! question "`char` 类型的长度是 1 字节吗?"

`char` 类型的长度由编程语言采用的编码方法决定。例如,Java、JavaScript、TypeScript、C# 都采用 UTF-16 编码(保存 Unicode 码点),因此 char 类型的长度为 2 字节。
`char` 类型的长度由编程语言采用的编码方法决定。例如,Java、JavaScript、TypeScript、C# 都采用 UTF-16 编码(保存 Unicode 码点),因此 `char` 类型的长度为 2 字节。

!!! question "基于数组实现的数据结构也称“静态数据结构” 是否有歧义?栈也可以进行出栈和入栈等操作,这些操作都是“动态”的。"

栈确实可以实现动态的数据操作,但数据结构仍然是“静态”(长度不可变)的。尽管基于数组的数据结构可以动态地添加或删除元素,但它们的容量是固定的。如果数据量超出了预分配的大小,就需要创建一个新的更大的数组,并将旧数组的内容复制到新数组中。

!!! question "在构建栈(队列)的时候,未指定它的大小,为什么它们是“静态数据结构”呢?"

在高级编程语言中,我们无须人工指定栈(队列)的初始容量,这个工作由类内部自动完成。例如,Java 的 ArrayList 的初始容量通常为 10。另外,扩容操作也是自动实现的。详见后续的“列表”章节。
在高级编程语言中,我们无须人工指定栈(队列)的初始容量,这个工作由类内部自动完成。例如,Java 的 `ArrayList` 的初始容量通常为 10。另外,扩容操作也是自动实现的。详见后续的“列表”章节。
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@

1. 前序遍历的首元素 3 是根节点的值。
2. 查找根节点 3 在 `inorder` 中的索引,利用该索引可将 `inorder` 划分为 `[ 9 | 3 | 1 2 7 ]`
3. 根据 `inorder` 划分结果,易得左子树和右子树的节点数量分别为 1 和 3 ,从而可将 `preorder` 划分为 `[ 3 | 9 | 2 1 7 ]`
3. 根据 `inorder` 的划分结果,易得左子树和右子树的节点数量分别为 1 和 3 ,从而可将 `preorder` 划分为 `[ 3 | 9 | 2 1 7 ]`

![在前序遍历和中序遍历中划分子树](build_binary_tree_problem.assets/build_tree_preorder_inorder_division.png)

Expand Down
4 changes: 2 additions & 2 deletions docs/chapter_hashing/hash_collision.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,6 @@

各种编程语言采取了不同的哈希表实现策略,下面举几个例子。

- Python 采用开放寻址。字典 dict 使用伪随机数进行探测。
- Java 采用链式地址。自 JDK 1.8 以来,当 HashMap 内数组长度达到 64 且链表长度达到 8 时,链表会转换为红黑树以提升查找性能。
- Python 采用开放寻址。字典 `dict` 使用伪随机数进行探测。
- Java 采用链式地址。自 JDK 1.8 以来,当 `HashMap` 内数组长度达到 64 且链表长度达到 8 时,链表会转换为红黑树以提升查找性能。
- Go 采用链式地址。Go 规定每个桶最多存储 8 个键值对,超出容量则连接一个溢出桶;当溢出桶过多时,会执行一次特殊的等量扩容操作,以确保性能。
18 changes: 9 additions & 9 deletions docs/chapter_heap/heap.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@

<p align="center"> 表 <id> &nbsp; 堆的操作效率 </p>

| 方法名 | 描述 | 时间复杂度 |
| ----------- | -------------------------------------------- | ----------- |
| `push()` | 元素入堆 | $O(\log n)$ |
| `pop()` | 堆顶元素出堆 | $O(\log n)$ |
| `peek()` | 访问堆顶元素( / 小顶堆分别为最大 / 小值) | $O(1)$ |
| `size()` | 获取堆的元素数量 | $O(1)$ |
| `isEmpty()` | 判断堆是否为空 | $O(1)$ |
| 方法名 | 描述 | 时间复杂度 |
| ----------- | ------------------------------------------------ | ----------- |
| `push()` | 元素入堆 | $O(\log n)$ |
| `pop()` | 堆顶元素出堆 | $O(\log n)$ |
| `peek()` | 访问堆顶元素(对于大 / 小顶堆分别为最大 / 小值) | $O(1)$ |
| `size()` | 获取堆的元素数量 | $O(1)$ |
| `isEmpty()` | 判断堆是否为空 | $O(1)$ |

在实际应用中,我们可以直接使用编程语言提供的堆类(或优先队列类)。

Expand Down Expand Up @@ -353,7 +353,7 @@

当使用数组表示二叉树时,元素代表节点值,索引代表节点在二叉树中的位置。**节点指针通过索引映射公式来实现**

如下图所示,给定索引 $i$ ,其左子节点索引为 $2i + 1$ ,右子节点索引为 $2i + 2$ ,父节点索引为 $(i - 1) / 2$(向下整除)。当索引越界时,表示空节点或节点不存在。
如下图所示,给定索引 $i$ ,其左子节点的索引为 $2i + 1$ ,右子节点的索引为 $2i + 2$ ,父节点的索引为 $(i - 1) / 2$(向下整除)。当索引越界时,表示空节点或节点不存在。

![堆的表示与存储](heap.assets/representation_of_heap.png)

Expand All @@ -373,7 +373,7 @@

### 元素入堆

给定元素 `val` ,我们首先将其添加到堆底。添加之后,由于 val 可能大于堆中其他元素,堆的成立条件可能已被破坏,**因此需要修复从插入节点到根节点的路径上的各个节点**,这个操作被称为「堆化 heapify」。
给定元素 `val` ,我们首先将其添加到堆底。添加之后,由于 `val` 可能大于堆中其他元素,堆的成立条件可能已被破坏,**因此需要修复从插入节点到根节点的路径上的各个节点**,这个操作被称为「堆化 heapify」。

考虑从入堆节点开始,**从底至顶执行堆化**。如下图所示,我们比较插入节点与其父节点的值,如果插入节点更大,则将它们交换。然后继续执行此操作,从底至顶修复堆中的各个节点,直至越过根节点或遇到无须交换的节点时结束。

Expand Down
2 changes: 1 addition & 1 deletion docs/chapter_searching/searching_algorithm_revisited.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,4 @@
- 适用于海量数据,因为树节点在内存中是分散存储的。
- 适合需要维护有序数据或范围查找的场景。
- 在持续增删节点的过程中,二叉搜索树可能产生倾斜,时间复杂度劣化至 $O(n)$ 。
- 若使用 AVL 树或红黑树,则各项操作可在 $O(\log n)$ 效率下稳定运行,但维护树平衡的操作会增加额外开销
- 若使用 AVL 树或红黑树,则各项操作可在 $O(\log n)$ 效率下稳定运行,但维护树平衡的操作会增加额外的开销
2 changes: 1 addition & 1 deletion docs/chapter_sorting/bubble_sort.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@

设数组的长度为 $n$ ,冒泡排序的步骤如下图所示。

1. 首先,对 $n$ 个元素执行“冒泡”,**将数组的最大元素交换至正确位置**
1. 首先,对 $n$ 个元素执行“冒泡”,**将数组的最大元素交换至正确位置**
2. 接下来,对剩余 $n - 1$ 个元素执行“冒泡”,**将第二大元素交换至正确位置**
3. 以此类推,经过 $n - 1$ 轮“冒泡”后,**前 $n - 1$ 大的元素都被交换至正确位置**
4. 仅剩的一个元素必定是最小元素,无须排序,因此数组排序完成。
Expand Down

0 comments on commit b52a840

Please sign in to comment.