diff --git a/docs/assets/covers/chapter_complexity_analysis.jpg b/docs/assets/covers/chapter_complexity_analysis.jpg index 2f2c382c2..be3d1cc43 100644 Binary files a/docs/assets/covers/chapter_complexity_analysis.jpg and b/docs/assets/covers/chapter_complexity_analysis.jpg differ diff --git a/docs/chapter_computational_complexity/index.md b/docs/chapter_computational_complexity/index.md index be7b7c6af..5867040c5 100644 --- a/docs/chapter_computational_complexity/index.md +++ b/docs/chapter_computational_complexity/index.md @@ -1,8 +1,8 @@ -# 时空复杂度 +# 复杂度分析
-![时空复杂度](../assets/covers/chapter_complexity_analysis.jpg){ width="600" } +![复杂度分析](../assets/covers/chapter_complexity_analysis.jpg){ width="600" }
diff --git a/docs/chapter_computational_complexity/performance_evaluation.md b/docs/chapter_computational_complexity/performance_evaluation.md index 5f3cc8b36..1d3766161 100644 --- a/docs/chapter_computational_complexity/performance_evaluation.md +++ b/docs/chapter_computational_complexity/performance_evaluation.md @@ -5,7 +5,7 @@ 1. **找到问题解法**:算法需要在规定的输入范围内,可靠地求得问题的正确解。 2. **寻求最优解法**:同一个问题可能存在多种解法,我们希望找到尽可能高效的算法。 -也就是说,在能够解决问题的前提下,算法效率是衡量算法优劣的主要评价指标,它包括以下两个维度。 +也就是说,在能够解决问题的前提下,算法效率已成为衡量算法优劣的主要评价指标,它包括以下两个维度。 - **时间效率**:算法运行速度的快慢。 - **空间效率**:算法占用内存空间的大小。 @@ -20,7 +20,7 @@ 一方面,**难以排除测试环境的干扰因素**。硬件配置会影响算法的性能表现。比如在某台计算机中,算法 `A` 的运行时间比算法 `B` 短;但在另一台配置不同的计算机中,我们可能得到相反的测试结果。这意味着我们需要在各种机器上进行测试,统计平均效率,而这是不现实的。 -另一方面,**展开完整测试非常耗费资源**。随着输入数据量的变化,算法会表现出不同的效率。例如,在输入数据量较小时,算法 `A` 的运行时间比算法 `B` 更少;而输入数据量较大时,测试结果可能恰恰相反。因此,为了得到有说服力的结论,我们需要测试各种规模的输入数据,而这样需要耗费大量的计算资源。 +另一方面,**展开完整测试非常耗费资源**。随着输入数据量的变化,算法会表现出不同的效率。例如,在输入数据量较小时,算法 `A` 的运行时间比算法 `B` 更少;而输入数据量较大时,测试结果可能恰恰相反。因此,为了得到有说服力的结论,我们需要测试各种规模的输入数据,而这需要耗费大量的计算资源。 ## 理论估算 diff --git a/docs/chapter_computational_complexity/space_complexity.md b/docs/chapter_computational_complexity/space_complexity.md index 1cbac9a32..59ae22ea7 100755 --- a/docs/chapter_computational_complexity/space_complexity.md +++ b/docs/chapter_computational_complexity/space_complexity.md @@ -663,10 +663,6 @@ $$ ![常见的空间复杂度类型](space_complexity.assets/space_complexity_common_types.png) -!!! tip - - 部分示例代码需要一些前置知识,包括数组、链表、二叉树、递归算法等。如果你遇到看不懂的地方,可以在学完后面章节后再来复习。 - ### 常数阶 $O(1)$ 常数阶常见于数量与输入数据大小 $n$ 无关的常量、变量、对象。 diff --git a/docs/chapter_computational_complexity/summary.md b/docs/chapter_computational_complexity/summary.md index b8d53fd41..9a627e81b 100644 --- a/docs/chapter_computational_complexity/summary.md +++ b/docs/chapter_computational_complexity/summary.md @@ -11,7 +11,7 @@ - 时间复杂度用于衡量算法运行时间随数据量增长的趋势,可以有效评估算法效率,但在某些情况下可能失效,如在输入的数据量较小或时间复杂度相同时,无法精确对比算法效率的优劣。 - 最差时间复杂度使用大 $O$ 符号表示,对应函数渐近上界,反映当 $n$ 趋向正无穷时,操作数量 $T(n)$ 的增长级别。 - 推算时间复杂度分为两步,首先统计操作数量,然后判断渐近上界。 -- 常见时间复杂度从小到大排列有 $O(1)$、$O(\log n)$、$O(n)$、$O(n \log n)$、$O(n^2)$、$O(2^n)$、$O(n!)$ 等。 +- 常见时间复杂度从小到大排列有 $O(1)$、$O(\log n)$、$O(n)$、$O(n \log n)$、$O(n^2)$、$O(2^n)$ 和 $O(n!)$ 等。 - 某些算法的时间复杂度非固定,而是与输入数据的分布有关。时间复杂度分为最差、最佳、平均时间复杂度,最佳时间复杂度几乎不用,因为输入数据一般需要满足严格条件才能达到最佳情况。 - 平均时间复杂度反映算法在随机数据输入下的运行效率,最接近实际应用中的算法性能。计算平均时间复杂度需要统计输入数据分布以及综合后的数学期望。 @@ -20,7 +20,7 @@ - 空间复杂度的作用类似于时间复杂度,用于衡量算法占用空间随数据量增长的趋势。 - 算法运行过程中的相关内存空间可分为输入空间、暂存空间、输出空间。通常情况下,输入空间不计入空间复杂度计算。暂存空间可分为指令空间、数据空间、栈帧空间,其中栈帧空间通常仅在递归函数中影响空间复杂度。 - 我们通常只关注最差空间复杂度,即统计算法在最差输入数据和最差运行时间点下的空间复杂度。 -- 常见空间复杂度从小到大排列有 $O(1)$、$O(\log n)$、$O(n)$、$O(n^2)$、$O(2^n)$ 等。 +- 常见空间复杂度从小到大排列有 $O(1)$、$O(\log n)$、$O(n)$、$O(n^2)$ 和 $O(2^n)$ 等。 ## Q & A @@ -38,7 +38,7 @@ - Java 和 C# 是面向对象的编程语言,代码块(方法)通常都是作为某个类的一部分。静态方法的行为类似于函数,因为它被绑定在类上,不能访问特定的实例变量。 - C++ 和 Python 既支持过程式编程(函数),也支持面向对象编程(方法)。 -!!! question "图“空间复杂度的常见类型”反映的是否是占用空间的绝对大小?" +!!! question "图“常见的空间复杂度类型”反映的是否是占用空间的绝对大小?" 不是,该图片展示的是空间复杂度,其反映的是增长趋势,而不是占用空间的绝对大小。 diff --git a/docs/chapter_computational_complexity/time_complexity.md b/docs/chapter_computational_complexity/time_complexity.md index 7cdbda901..816b2bf1b 100755 --- a/docs/chapter_computational_complexity/time_complexity.md +++ b/docs/chapter_computational_complexity/time_complexity.md @@ -613,18 +613,11 @@ $T(n)$ 是一次函数,说明其运行时间的增长趋势是线性的,因 我们将线性阶的时间复杂度记为 $O(n)$ ,这个数学符号称为「大 $O$ 记号 big-$O$ notation」,表示函数 $T(n)$ 的「渐近上界 asymptotic upper bound」。 -时间复杂度分析本质上是计算“操作数量函数 $T(n)$”的渐近上界。接下来,我们来看函数渐近上界的数学定义。 +时间复杂度分析本质上是计算“操作数量函数 $T(n)$”的渐近上界,其具有明确的数学定义。 !!! abstract "函数渐近上界" - 若存在正实数 $c$ 和实数 $n_0$ ,使得对于所有的 $n > n_0$ ,均有 - $$ - T(n) \leq c \cdot f(n) - $$ - 则可认为 $f(n)$ 给出了 $T(n)$ 的一个渐近上界,记为 - $$ - T(n) = O(f(n)) - $$ + 若存在正实数 $c$ 和实数 $n_0$ ,使得对于所有的 $n > n_0$ ,均有 $T(n) \leq c \cdot f(n)$ ,则可认为 $f(n)$ 给出了 $T(n)$ 的一个渐近上界,记为 $T(n) = O(f(n))$ 。 如下图所示,计算渐近上界就是寻找一个函数 $f(n)$ ,使得当 $n$ 趋向于无穷大时,$T(n)$ 和 $f(n)$ 处于相同的增长级别,仅相差一个常数项 $c$ 的倍数。 @@ -642,17 +635,9 @@ $T(n)$ 是一次函数,说明其运行时间的增长趋势是线性的,因 1. **忽略 $T(n)$ 中的常数项**。因为它们都与 $n$ 无关,所以对时间复杂度不产生影响。 2. **省略所有系数**。例如,循环 $2n$ 次、$5n + 1$ 次等,都可以简化记为 $n$ 次,因为 $n$ 前面的系数对时间复杂度没有影响。 -3. **循环嵌套时使用乘法**。总操作数量等于外层循环和内层循环操作数量之积,每一层循环依然可以分别套用上述 `1.` 和 `2.` 技巧。 - -以下代码与公式分别展示了使用上述技巧前后的统计结果。两者推出的时间复杂度相同,都为 $O(n^2)$ 。 +3. **循环嵌套时使用乘法**。总操作数量等于外层循环和内层循环操作数量之积,每一层循环依然可以分别套用第 `1.` 点和第 `2.` 点的技巧。、 -$$ -\begin{aligned} -T(n) & = 2n(n + 1) + (5n + 1) + 2 & \text{完整统计 (-.-|||)} \newline -& = 2n^2 + 7n + 3 \newline -T(n) & = n^2 + n & \text{偷懒统计 (o.O)} -\end{aligned} -$$ +给定一个函数,我们可以用上述技巧来统计操作数量。 === "Java" @@ -867,6 +852,16 @@ $$ } ``` +以下公式展示了使用上述技巧前后的统计结果,两者推出的时间复杂度都为 $O(n^2)$ 。 + +$$ +\begin{aligned} +T(n) & = 2n(n + 1) + (5n + 1) + 2 & \text{完整统计 (-.-|||)} \newline +& = 2n^2 + 7n + 3 \newline +T(n) & = n^2 + n & \text{偷懒统计 (o.O)} +\end{aligned} +$$ + ### 第二步:判断渐近上界 **时间复杂度由多项式 $T(n)$ 中最高阶的项来决定**。这是因为在 $n$ 趋于无穷大时,最高阶的项将发挥主导作用,其他项的影响都可以被忽略。 @@ -896,15 +891,11 @@ $$ ![常见的时间复杂度类型](time_complexity.assets/time_complexity_common_types.png) -!!! tip - - 部分示例代码需要一些预备知识,包括数组、递归等。如果你遇到不理解的部分,可以在学完后面章节后再回顾。现阶段,请先专注于理解时间复杂度的含义和推算方法。 - ### 常数阶 $O(1)$ 常数阶的操作数量与输入数据大小 $n$ 无关,即不随着 $n$ 的变化而变化。 -对于以下算法,尽管操作数量 `size` 可能很大,但由于其与输入数据大小 $n$ 无关,因此时间复杂度仍为 $O(1)$ : +在以下函数中,尽管操作数量 `size` 可能很大,但由于其与输入数据大小 $n$ 无关,因此时间复杂度仍为 $O(1)$ : === "Java" @@ -1132,7 +1123,7 @@ $$ ### 平方阶 $O(n^2)$ -平方阶的操作数量相对于输入数据大小以平方级别增长。平方阶通常出现在嵌套循环中,外层循环和内层循环都为 $O(n)$ ,因此总体为 $O(n^2)$ : +平方阶的操作数量相对于输入数据大小 $n$ 以平方级别增长。平方阶通常出现在嵌套循环中,外层循环和内层循环都为 $O(n)$ ,因此总体为 $O(n^2)$ : === "Java" @@ -1776,7 +1767,7 @@ $$ ## 最差、最佳、平均时间复杂度 -**算法的时间效率往往不是固定的,而是与输入数据的分布有关**。假设输入一个长度为 $n$ 的数组 `nums` ,其中 `nums` 由从 $1$ 至 $n$ 的数字组成,每个数字只出现一次,但元素顺序是随机打乱的,任务目标是返回元素 $1$ 的索引。我们可以得出以下结论。 +**算法的时间效率往往不是固定的,而是与输入数据的分布有关**。假设输入一个长度为 $n$ 的数组 `nums` ,其中 `nums` 由从 $1$ 至 $n$ 的数字组成,每个数字只出现一次;但元素顺序是随机打乱的,任务目标是返回元素 $1$ 的索引。我们可以得出以下结论。 - 当 `nums = [?, ?, ..., 1]` ,即当末尾元素是 $1$ 时,需要完整遍历数组,**达到最差时间复杂度 $O(n)$** 。 - 当 `nums = [1, ?, ?, ...]` ,即当首个元素为 $1$ 时,无论数组多长都不需要继续遍历,**达到最佳时间复杂度 $\Omega(1)$** 。 diff --git a/docs/chapter_introduction/algorithms_are_everywhere.md b/docs/chapter_introduction/algorithms_are_everywhere.md index a3a4baaa2..2a3ceb153 100644 --- a/docs/chapter_introduction/algorithms_are_everywhere.md +++ b/docs/chapter_introduction/algorithms_are_everywhere.md @@ -37,7 +37,7 @@ 上述整理扑克牌的方法本质上是“插入排序”算法,它在处理小型数据集时非常高效。许多编程语言的排序库函数中都存在插入排序的身影。 -**例三:货币找零**。假设我们在超市购买了 $69$ 元的商品,给收银员付了 $100$ 元,则收银员需要找我们 $31$ 元。他会很自然地完成下图所示的思考。 +**例三:货币找零**。假设我们在超市购买了 $69$ 元的商品,给了收银员 $100$ 元,则收银员需要找我们 $31$ 元。他会很自然地完成如下图所示的思考。 1. 可选项是比 $31$ 元面值更小的货币,包括 $1$ 元、$5$ 元、$10$ 元、$20$ 元。 2. 从可选项中拿出最大的 $20$ 元,剩余 $31 - 20 = 11$ 元。 @@ -53,4 +53,4 @@ !!! tip - 如果你对数据结构、算法、数组和二分查找等概念仍感到一知半解,请不要担心,继续往下阅读,这本书将引导你迈入数据结构与算法的知识殿堂。 + 如果你对数据结构、算法、数组和二分查找等概念仍感到一知半解,请继续往下阅读,这本书将引导你迈入数据结构与算法的知识殿堂。 diff --git a/docs/chapter_introduction/what_is_dsa.md b/docs/chapter_introduction/what_is_dsa.md index bc84bc7c1..69d493b5f 100644 --- a/docs/chapter_introduction/what_is_dsa.md +++ b/docs/chapter_introduction/what_is_dsa.md @@ -23,7 +23,7 @@ ## 数据结构与算法的关系 -数据结构与算法高度相关、紧密结合,具体表现在下图所示的几个方面。 +如下图所示,数据结构与算法高度相关、紧密结合,具体表现以下三个方面。 - 数据结构是算法的基石。数据结构为算法提供了结构化存储的数据,以及用于操作数据的方法。 - 算法是数据结构发挥作用的舞台。数据结构本身仅存储数据信息,结合算法才能解决特定问题。 diff --git a/mkdocs.yml b/mkdocs.yml index c92d8f3d9..89274595a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -144,7 +144,7 @@ nav: - 1.1   算法无处不在: chapter_introduction/algorithms_are_everywhere.md - 1.2   算法是什么: chapter_introduction/what_is_dsa.md - 1.3   小结: chapter_introduction/summary.md - - 第 2 章   时空复杂度: + - 第 2 章   复杂度分析: # [icon: material/timer-sand] - chapter_computational_complexity/index.md - 2.1   算法效率评估: chapter_computational_complexity/performance_evaluation.md