Mention figures and tables in normal texts.

Fix some figures.
Finetune texts.
This commit is contained in:
krahets
2023-08-21 19:33:45 +08:00
parent 1aff6d6cc2
commit 106f02809a
64 changed files with 277 additions and 240 deletions

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 73 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 82 KiB

View File

@@ -671,7 +671,7 @@ $$
常数阶常见于数量与输入数据大小 $n$ 无关的常量、变量、对象。
需要注意的是,在循环中初始化变量或调用函数而占用的内存,在进入下一循环后就会被释放,不会累积占用空间,空间复杂度仍为 $O(1)$
需要注意的是,在循环中初始化变量或调用函数而占用的内存,在进入下一循环后就会被释放,因此不会累积占用空间,空间复杂度仍为 $O(1)$
=== "Java"
@@ -847,7 +847,7 @@ $$
[class]{}-[func]{linear}
```
以下函数的递归深度为 $n$ ,即同时存在 $n$ 个未返回的 `linear_recur()` 函数,使用 $O(n)$ 大小的栈帧空间:
如下图所示,此函数的递归深度为 $n$ ,即同时存在 $n$ 个未返回的 `linear_recur()` 函数,使用 $O(n)$ 大小的栈帧空间:
=== "Java"
@@ -999,7 +999,7 @@ $$
[class]{}-[func]{quadratic}
```
以下函数的递归深度为 $n$ ,在每个递归函数中都初始化了一个数组,长度分别为 $n, n-1, n-2, ..., 2, 1$ ,平均长度为 $n / 2$ ,因此总体占用 $O(n^2)$ 空间
如下图所示,该函数的递归深度为 $n$ ,在每个递归函数中都初始化了一个数组,长度分别为 $n, n-1, n-2, ..., 2, 1$ ,平均长度为 $n / 2$ ,因此总体占用 $O(n^2)$ 空间
=== "Java"
@@ -1077,7 +1077,7 @@ $$
### 指数阶 $O(2^n)$
指数阶常见于二叉树。高度为 $n$ 的“满二叉树”的节点数量为 $2^n - 1$ ,占用 $O(2^n)$ 空间:
指数阶常见于二叉树。观察下图,高度为 $n$ 的“满二叉树”的节点数量为 $2^n - 1$ ,占用 $O(2^n)$ 空间:
=== "Java"

View File

@@ -426,11 +426,11 @@ $$
}
```
算法 `A` 只有 $1$ 个打印操作,算法运行时间不随着 $n$ 增大而增长。我们称此算法的时间复杂度为“常数阶”
下图展示了以上三个算法函数的时间复杂度
算法 `B` 中的打印操作需要循环 $n$ ,算法运行时间随着 $n$ 增大呈线性增长。此算法的时间复杂度被称为“线性阶”。
算法 `C` 中的打印操作需要循环 $1000000$ 次,虽然运行时间很长,但它与输入数据大小 $n$ 无关。因此 `C` 的时间复杂度和 `A` 相同,仍为“常数阶”。
- 算法 `A` 只有 $1$ 个打印操作,算法运行时间随着 $n$ 增大而增长。我们称此算法的时间复杂度为“常数阶”。
- 算法 `B` 中的打印操作需要循环 $n$ 次,算法运行时间随着 $n$ 增大呈线性增长。此算法的时间复杂度被称为“线性阶”。
- 算法 `C` 中的打印操作需要循环 $1000000$ 次,虽然运行时间很长,但它与输入数据大小 $n$ 无关。因此 `C` 的时间复杂度和 `A` 相同,仍为“常数阶”。
![算法 A 、B 和 C 的时间增长趋势](time_complexity.assets/time_complexity_simple_example.png)
@@ -871,7 +871,7 @@ $$
**时间复杂度由多项式 $T(n)$ 中最高阶的项来决定**。这是因为在 $n$ 趋于无穷大时,最高阶的项将发挥主导作用,其他项的影响都可以被忽略。
下表展示了一些例子,其中一些夸张的值是为了强调“系数无法撼动阶数”这一结论。当 $n$ 趋于无穷大时,这些常数变得无足轻重。
下表展示了一些例子,其中一些夸张的值是为了强调“系数无法撼动阶数”这一结论。当 $n$ 趋于无穷大时,这些常数变得无足轻重。
<p align="center"> 表:不同操作数量对应的时间复杂度 </p>
@@ -885,7 +885,7 @@ $$
## 常见类型
设输入数据大小为 $n$ ,常见的时间复杂度类型包括(按照从低到高的顺序排列)
设输入数据大小为 $n$ ,常见的时间复杂度类型如下图所示(按照从低到高的顺序排列)
$$
\begin{aligned}
@@ -1286,7 +1286,9 @@ $$
### 指数阶 $O(2^n)$
生物学的“细胞分裂”是指数阶增长的典型例子:初始状态为 $1$ 个细胞,分裂一轮后变为 $2$ 个,分裂两轮后变为 $4$ 个,以此类推,分裂 $n$ 轮后有 $2^n$ 个细胞。相关代码如下:
生物学的“细胞分裂”是指数阶增长的典型例子:初始状态为 $1$ 个细胞,分裂一轮后变为 $2$ 个,分裂两轮后变为 $4$ 个,以此类推,分裂 $n$ 轮后有 $2^n$ 个细胞。
以下代码和图模拟了细胞分裂的过程,时间复杂度为 $O(2^n)$ 。
=== "Java"
@@ -1360,11 +1362,9 @@ $$
[class]{}-[func]{exponential}
```
下图展示了细胞分裂的过程。
![指数阶的时间复杂度](time_complexity.assets/time_complexity_exponential.png)
在实际算法中,指数阶常出现于递归函数中。例如以下代码,其递归地一分为二,经过 $n$ 次分裂后停止:
在实际算法中,指数阶常出现于递归函数中。例如以下代码,其递归地一分为二,经过 $n$ 次分裂后停止:
=== "Java"
@@ -1442,7 +1442,9 @@ $$
### 对数阶 $O(\log n)$
与指数阶相反,对数阶反映了“每轮缩减到一半”的情况。设输入数据大小为 $n$ ,由于每轮缩减到一半,因此循环次数是 $\log_2 n$ ,即 $2^n$ 的反函数。相关代码如下:
与指数阶相反,对数阶反映了“每轮缩减到一半”的情况。设输入数据大小为 $n$ ,由于每轮缩减到一半,因此循环次数是 $\log_2 n$ ,即 $2^n$ 的反函数。
以下代码和图模拟了“每轮缩减到一半”的过程,时间复杂度为 $O(\log_2 n)$ ,简记为 $O(\log n)$ 。
=== "Java"
@@ -1602,7 +1604,7 @@ $$
O(\log_m n) = O(\log_k n / \log_k m) = O(\log_k n)
$$
因此我们通常会省略底数 $m$ ,将对数阶直接记为 $O(\log n)$ 。
也就是说,底数 $m$ 可以在不影响复杂度的前提下转换。因此我们通常会省略底数 $m$ ,将对数阶直接记为 $O(\log n)$ 。
### 线性对数阶 $O(n \log n)$
@@ -1680,6 +1682,8 @@ $$
[class]{}-[func]{linear_log_recur}
```
下图展示了线性对数阶的生成方式。二叉树的每一层的操作总数都为 $n$ ,树共有 $\log_2 n + 1$ 层,因此时间复杂度为 $O(n \log n)$ 。
![线性对数阶的时间复杂度](time_complexity.assets/time_complexity_logarithmic_linear.png)
主流排序算法的时间复杂度通常为 $O(n \log n)$ ,例如快速排序、归并排序、堆排序等。
@@ -1692,7 +1696,7 @@ $$
n! = n \times (n - 1) \times (n - 2) \times \dots \times 2 \times 1
$$
阶乘通常使用递归实现。例如在以下代码,第一层分裂出 $n$ 个,第二层分裂出 $n - 1$ 个,以此类推,直至第 $n$ 层时停止分裂:
阶乘通常使用递归实现。如下图和以下代码所示,第一层分裂出 $n$ 个,第二层分裂出 $n - 1$ 个,以此类推,直至第 $n$ 层时停止分裂:
=== "Java"