From f5dda8d99a280b5ded1000e363da8b4f275d10a7 Mon Sep 17 00:00:00 2001 From: krahets Date: Mon, 21 Aug 2023 03:06:53 +0800 Subject: [PATCH] Polish the content --- .../space_complexity.c | 2 +- .../space_complexity.cpp | 2 +- .../space_complexity.cs | 2 +- .../space_complexity.dart | 2 +- .../space_complexity.go | 2 +- .../space_complexity.java | 2 +- .../space_complexity.js | 2 +- .../space_complexity.py | 2 +- .../space_complexity.rs | 2 +- .../space_complexity.swift | 2 +- .../space_complexity.ts | 2 +- .../space_complexity.zig | 2 +- .../space_complexity.md | 50 +++++++++---------- .../time_complexity.md | 16 +++--- .../divide_and_conquer.md | 2 +- docs/chapter_introduction/what_is_dsa.md | 2 +- docs/chapter_sorting/bubble_sort.md | 2 +- docs/chapter_sorting/quick_sort.md | 2 +- docs/chapter_tree/binary_tree_traversal.md | 2 +- 19 files changed, 49 insertions(+), 51 deletions(-) diff --git a/codes/c/chapter_computational_complexity/space_complexity.c b/codes/c/chapter_computational_complexity/space_complexity.c index f5b2141c6..8cc667d85 100644 --- a/codes/c/chapter_computational_complexity/space_complexity.c +++ b/codes/c/chapter_computational_complexity/space_complexity.c @@ -8,7 +8,7 @@ /* 函数 */ int func() { - // do something + // 执行某些操作 return 0; } diff --git a/codes/cpp/chapter_computational_complexity/space_complexity.cpp b/codes/cpp/chapter_computational_complexity/space_complexity.cpp index d0e284e0b..34f315e84 100644 --- a/codes/cpp/chapter_computational_complexity/space_complexity.cpp +++ b/codes/cpp/chapter_computational_complexity/space_complexity.cpp @@ -8,7 +8,7 @@ /* 函数 */ int func() { - // do something + // 执行某些操作 return 0; } diff --git a/codes/csharp/chapter_computational_complexity/space_complexity.cs b/codes/csharp/chapter_computational_complexity/space_complexity.cs index 993851a82..b88f88ea6 100644 --- a/codes/csharp/chapter_computational_complexity/space_complexity.cs +++ b/codes/csharp/chapter_computational_complexity/space_complexity.cs @@ -9,7 +9,7 @@ namespace hello_algo.chapter_computational_complexity; public class space_complexity { /* 函数 */ static int function() { - // do something + // 执行某些操作 return 0; } diff --git a/codes/dart/chapter_computational_complexity/space_complexity.dart b/codes/dart/chapter_computational_complexity/space_complexity.dart index 099fcf711..b6b83fc1e 100644 --- a/codes/dart/chapter_computational_complexity/space_complexity.dart +++ b/codes/dart/chapter_computational_complexity/space_complexity.dart @@ -11,7 +11,7 @@ import '../utils/tree_node.dart'; /* 函数 */ int function() { - // do something + // 执行某些操作 return 0; } diff --git a/codes/go/chapter_computational_complexity/space_complexity.go b/codes/go/chapter_computational_complexity/space_complexity.go index 93f5b3380..aaad21404 100644 --- a/codes/go/chapter_computational_complexity/space_complexity.go +++ b/codes/go/chapter_computational_complexity/space_complexity.go @@ -44,7 +44,7 @@ func printTree(root *treeNode) { /* 函数 */ func function() int { - // do something... + // 执行某些操作... return 0 } diff --git a/codes/java/chapter_computational_complexity/space_complexity.java b/codes/java/chapter_computational_complexity/space_complexity.java index e7c0872f1..d73b8c2cb 100644 --- a/codes/java/chapter_computational_complexity/space_complexity.java +++ b/codes/java/chapter_computational_complexity/space_complexity.java @@ -12,7 +12,7 @@ import java.util.*; public class space_complexity { /* 函数 */ static int function() { - // do something + // 执行某些操作 return 0; } diff --git a/codes/javascript/chapter_computational_complexity/space_complexity.js b/codes/javascript/chapter_computational_complexity/space_complexity.js index bdbba6642..7708eaabb 100644 --- a/codes/javascript/chapter_computational_complexity/space_complexity.js +++ b/codes/javascript/chapter_computational_complexity/space_complexity.js @@ -10,7 +10,7 @@ const { printTree } = require('../modules/PrintUtil'); /* 函数 */ function constFunc() { - // do something + // 执行某些操作 return 0; } diff --git a/codes/python/chapter_computational_complexity/space_complexity.py b/codes/python/chapter_computational_complexity/space_complexity.py index dc8c9a623..6b4cb90b0 100644 --- a/codes/python/chapter_computational_complexity/space_complexity.py +++ b/codes/python/chapter_computational_complexity/space_complexity.py @@ -12,7 +12,7 @@ from modules import * def function() -> int: """函数""" - # do something + # 执行某些操作 return 0 diff --git a/codes/rust/chapter_computational_complexity/space_complexity.rs b/codes/rust/chapter_computational_complexity/space_complexity.rs index 82758f201..1cf8dff9b 100644 --- a/codes/rust/chapter_computational_complexity/space_complexity.rs +++ b/codes/rust/chapter_computational_complexity/space_complexity.rs @@ -14,7 +14,7 @@ use tree_node::TreeNode; /* 函数 */ fn function() ->i32 { - // do something + // 执行某些操作 return 0; } diff --git a/codes/swift/chapter_computational_complexity/space_complexity.swift b/codes/swift/chapter_computational_complexity/space_complexity.swift index fdd29f8e2..e35429ba4 100644 --- a/codes/swift/chapter_computational_complexity/space_complexity.swift +++ b/codes/swift/chapter_computational_complexity/space_complexity.swift @@ -9,7 +9,7 @@ import utils /* 函数 */ @discardableResult func function() -> Int { - // do something + // 执行某些操作 return 0 } diff --git a/codes/typescript/chapter_computational_complexity/space_complexity.ts b/codes/typescript/chapter_computational_complexity/space_complexity.ts index 8324d4ca2..ab4849781 100644 --- a/codes/typescript/chapter_computational_complexity/space_complexity.ts +++ b/codes/typescript/chapter_computational_complexity/space_complexity.ts @@ -10,7 +10,7 @@ import { printTree } from '../modules/PrintUtil'; /* 函数 */ function constFunc(): number { - // do something + // 执行某些操作 return 0; } diff --git a/codes/zig/chapter_computational_complexity/space_complexity.zig b/codes/zig/chapter_computational_complexity/space_complexity.zig index b301d5fa7..e4d753000 100644 --- a/codes/zig/chapter_computational_complexity/space_complexity.zig +++ b/codes/zig/chapter_computational_complexity/space_complexity.zig @@ -7,7 +7,7 @@ const inc = @import("include"); // 函数 fn function() i32 { - // do something + // 执行某些操作 return 0; } diff --git a/docs/chapter_computational_complexity/space_complexity.md b/docs/chapter_computational_complexity/space_complexity.md index 5ee66c2c3..d938c91d8 100755 --- a/docs/chapter_computational_complexity/space_complexity.md +++ b/docs/chapter_computational_complexity/space_complexity.md @@ -34,7 +34,7 @@ /* 函数 */ int function() { - // do something... + // 执行某些操作... return 0; } @@ -59,7 +59,7 @@ /* 函数 */ int func() { - // do something... + // 执行某些操作... return 0; } @@ -83,7 +83,7 @@ def function() -> int: """函数""" - # do something... + # 执行某些操作... return 0 def algorithm(n) -> int: # 输入数据 @@ -110,7 +110,7 @@ /* 函数 */ func function() int { - // do something... + // 执行某些操作... return 0 } @@ -138,7 +138,7 @@ /* 函数 */ function constFunc() { - // do something + // 执行某些操作 return 0; } @@ -166,7 +166,7 @@ /* 函数 */ function constFunc(): number { - // do something + // 执行某些操作 return 0; } @@ -184,7 +184,7 @@ ```c title="" /* 函数 */ int func() { - // do something... + // 执行某些操作... return 0; } @@ -208,7 +208,7 @@ /* 函数 */ int function() { - // do something... + // 执行某些操作... return 0; } @@ -236,7 +236,7 @@ /* 函数 */ func function() -> Int { - // do something... + // 执行某些操作... return 0 } @@ -267,7 +267,7 @@ /* 函数 */ int function() { - // do something... + // 执行某些操作... return 0; } @@ -435,7 +435,7 @@ ```java title="" int function() { - // do something + // 执行某些操作 return 0; } /* 循环 O(1) */ @@ -455,7 +455,7 @@ ```cpp title="" int func() { - // do something + // 执行某些操作 return 0; } /* 循环 O(1) */ @@ -475,7 +475,7 @@ ```python title="" def function() -> int: - # do something + # 执行某些操作 return 0 def loop(n: int): @@ -493,7 +493,7 @@ ```go title="" func function() int { - // do something + // 执行某些操作 return 0 } @@ -517,7 +517,7 @@ ```javascript title="" function constFunc() { - // do something + // 执行某些操作 return 0; } /* 循环 O(1) */ @@ -537,7 +537,7 @@ ```typescript title="" function constFunc(): number { - // do something + // 执行某些操作 return 0; } /* 循环 O(1) */ @@ -557,7 +557,7 @@ ```c title="" int func() { - // do something + // 执行某些操作 return 0; } /* 循环 O(1) */ @@ -577,7 +577,7 @@ ```csharp title="" int function() { - // do something + // 执行某些操作 return 0; } /* 循环 O(1) */ @@ -598,7 +598,7 @@ ```swift title="" @discardableResult func function() -> Int { - // do something + // 执行某些操作 return 0 } @@ -628,7 +628,7 @@ ```dart title="" int function() { - // do something + // 执行某些操作 return 0; } /* 循环 O(1) */ @@ -847,7 +847,7 @@ $$ [class]{}-[func]{linear} ``` -以下递归函数会同时存在 $n$ 个未返回的 `algorithm()` 函数,使用 $O(n)$ 大小的栈帧空间: +以下函数的递归深度为 $n$ ,即同时存在 $n$ 个未返回的 `linear_recur()` 函数,使用 $O(n)$ 大小的栈帧空间: === "Java" @@ -999,7 +999,7 @@ $$ [class]{}-[func]{quadratic} ``` -在以下递归函数中,同时存在 $n$ 个未返回的 `algorithm()` ,并且每个函数中都初始化了一个数组,长度分别为 $n, n-1, n-2, ..., 2, 1$ ,平均长度为 $\frac{n}{2}$ ,因此总体占用 $O(n^2)$ 空间。 +以下函数的递归深度为 $n$ ,在每个递归函数中都初始化了一个数组,长度分别为 $n, n-1, n-2, ..., 2, 1$ ,平均长度为 $n / 2$ ,因此总体占用 $O(n^2)$ 空间。 === "Java" @@ -1155,11 +1155,9 @@ $$ ### 对数阶 $O(\log n)$ -对数阶常见于分治算法和数据类型转换等。 +对数阶常见于分治算法。例如归并排序,输入长度为 $n$ 的数组,每轮递归将数组从中点划分为两半,形成高度为 $\log n$ 的递归树,使用 $O(\log n)$ 栈帧空间。 -例如归并排序算法,输入长度为 $n$ 的数组,每轮递归将数组从中点划分为两半,形成高度为 $\log n$ 的递归树,使用 $O(\log n)$ 栈帧空间。 - -再例如将数字转化为字符串,输入任意正整数 $n$ ,它的位数为 $\log_{10} n + 1$ ,即对应字符串长度为 $\log_{10} n + 1$ ,因此空间复杂度为 $O(\log_{10} n + 1) = O(\log n)$ 。 +再例如将数字转化为字符串,输入一个正整数 $n$ ,它的位数为 $\log_{10} n + 1$ ,即对应字符串长度为 $\log_{10} n + 1$ ,因此空间复杂度为 $O(\log_{10} n + 1) = O(\log n)$ 。 ## 权衡时间与空间 diff --git a/docs/chapter_computational_complexity/time_complexity.md b/docs/chapter_computational_complexity/time_complexity.md index 14acb162e..e9f77c4a8 100755 --- a/docs/chapter_computational_complexity/time_complexity.md +++ b/docs/chapter_computational_complexity/time_complexity.md @@ -1210,11 +1210,7 @@ $$ ![常数阶、线性阶和平方阶的时间复杂度](time_complexity.assets/time_complexity_constant_linear_quadratic.png) -以冒泡排序为例,外层循环执行 $n - 1$ 次,内层循环执行 $n-1, n-2, \cdots, 2, 1$ 次,平均为 $\frac{n}{2}$ 次,因此时间复杂度为 $O(n^2)$ : - -$$ -O((n - 1) \frac{n}{2}) = O(n^2) -$$ +以冒泡排序为例,外层循环执行 $n - 1$ 次,内层循环执行 $n-1, n-2, \cdots, 2, 1$ 次,平均为 $n / 2$ 次,因此时间复杂度为 $O((n - 1) n / 2) = O(n^2)$ 。 === "Java" @@ -1596,7 +1592,11 @@ $$ [class]{}-[func]{log_recur} ``` -对数阶常出现于基于分治策略的算法中,体现了“一分为多”和“化繁为简”的算法思想。它增长缓慢,是理想的时间复杂度,仅次于常数阶。 +对数阶常出现于基于分治策略的算法中,体现了“一分为多”和“化繁为简”的算法思想。它增长缓慢,是仅次于常数阶的理想的时间复杂度。 + +!!! tip + + “一分为 $m$”对应的时间复杂度 $O(\log_m n)$ 。我们通常会省略底数 $m$ ,直接将其记为 $O(\log n)$ 。 ### 线性对数阶 $O(n \log n)$ @@ -1762,7 +1762,7 @@ $$ ![阶乘阶的时间复杂度](time_complexity.assets/time_complexity_factorial.png) -请注意,因为 $n! > 2^n$ ,所以阶乘阶比指数阶增长得更快,在 $n$ 较大时也是不可接受的。 +请注意,因为当 $n \geq 4$ 时恒有 $n! > 2^n$ ,所以阶乘阶比指数阶增长得更快,在 $n$ 较大时也是不可接受的。 ## 最差、最佳、平均时间复杂度 @@ -1892,7 +1892,7 @@ $$ 从上述示例可以看出,最差或最佳时间复杂度只出现于“特殊的数据分布”,这些情况的出现概率可能很小,并不能真实地反映算法运行效率。相比之下,**平均时间复杂度可以体现算法在随机输入数据下的运行效率**,用 $\Theta$ 记号来表示。 -对于部分算法,我们可以简单地推算出随机数据分布下的平均情况。比如上述示例,由于输入数组是被打乱的,因此元素 $1$ 出现在任意索引的概率都是相等的,那么算法的平均循环次数就是数组长度的一半 $\frac{n}{2}$ ,平均时间复杂度为 $\Theta(\frac{n}{2}) = \Theta(n)$ 。 +对于部分算法,我们可以简单地推算出随机数据分布下的平均情况。比如上述示例,由于输入数组是被打乱的,因此元素 $1$ 出现在任意索引的概率都是相等的,那么算法的平均循环次数就是数组长度的一半 $n / 2$ ,平均时间复杂度为 $\Theta(n / 2) = \Theta(n)$ 。 但对于较为复杂的算法,计算平均时间复杂度往往是比较困难的,因为很难分析出在数据分布下的整体数学期望。在这种情况下,我们通常使用最差时间复杂度作为算法效率的评判标准。 diff --git a/docs/chapter_divide_and_conquer/divide_and_conquer.md b/docs/chapter_divide_and_conquer/divide_and_conquer.md index 8010becef..46f723577 100644 --- a/docs/chapter_divide_and_conquer/divide_and_conquer.md +++ b/docs/chapter_divide_and_conquer/divide_and_conquer.md @@ -34,7 +34,7 @@ ### 操作数量优化 -以“冒泡排序”为例,其处理一个长度为 $n$ 的数组需要 $O(n^2)$ 时间。假设我们把数组从中点分为两个子数组,则划分需要 $O(n)$ 时间,排序每个子数组需要 $O((\frac{n}{2})^2)$ 时间,合并两个子数组需要 $O(n)$ 时间,总体时间复杂度为: +以“冒泡排序”为例,其处理一个长度为 $n$ 的数组需要 $O(n^2)$ 时间。假设我们把数组从中点分为两个子数组,则划分需要 $O(n)$ 时间,排序每个子数组需要 $O((n / 2)^2)$ 时间,合并两个子数组需要 $O(n)$ 时间,总体时间复杂度为: $$ O(n + (\frac{n}{2})^2 \times 2 + n) = O(\frac{n^2}{2} + 2n) diff --git a/docs/chapter_introduction/what_is_dsa.md b/docs/chapter_introduction/what_is_dsa.md index 06b6d20a6..05eb6fbb2 100644 --- a/docs/chapter_introduction/what_is_dsa.md +++ b/docs/chapter_introduction/what_is_dsa.md @@ -26,7 +26,7 @@ 数据结构与算法高度相关、紧密结合,具体表现在以下几个方面。 - 数据结构是算法的基石。数据结构为算法提供了结构化存储的数据,以及用于操作数据的方法。 -- 算法是数据结构发挥作用的舞台。数据结构本身仅存储数据信息,通过结合算法才能解决特定问题。 +- 算法是数据结构发挥作用的舞台。数据结构本身仅存储数据信息,结合算法才能解决特定问题。 - 特定算法通常会有对应最优的数据结构。算法通常可以基于不同的数据结构进行实现,但最终执行效率可能相差很大。 ![数据结构与算法的关系](what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png) diff --git a/docs/chapter_sorting/bubble_sort.md b/docs/chapter_sorting/bubble_sort.md index 65d568e00..b3c4d86e5 100755 --- a/docs/chapter_sorting/bubble_sort.md +++ b/docs/chapter_sorting/bubble_sort.md @@ -188,6 +188,6 @@ ## 算法特性 -- **时间复杂度为 $O(n^2)$ 、自适应排序** :各轮“冒泡”遍历的数组长度依次为 $n - 1$ , $n - 2$ , $\cdots$ , $2$ , $1$ ,总和为 $\frac{(n - 1) n}{2}$ 。在引入 `flag` 优化后,最佳时间复杂度可达到 $O(n)$ 。 +- **时间复杂度为 $O(n^2)$ 、自适应排序** :各轮“冒泡”遍历的数组长度依次为 $n - 1$ , $n - 2$ , $\cdots$ , $2$ , $1$ ,总和为 $(n - 1) n / 2$ 。在引入 `flag` 优化后,最佳时间复杂度可达到 $O(n)$ 。 - **空间复杂度为 $O(1)$ 、原地排序**:指针 $i$ , $j$ 使用常数大小的额外空间。 - **稳定排序**:由于在“冒泡”中遇到相等元素不交换。 diff --git a/docs/chapter_sorting/quick_sort.md b/docs/chapter_sorting/quick_sort.md index 7d70f08db..da65a1a7d 100755 --- a/docs/chapter_sorting/quick_sort.md +++ b/docs/chapter_sorting/quick_sort.md @@ -335,7 +335,7 @@ **在某些输入下,快速排序可能占用空间较多**。以完全倒序的输入数组为例,由于每轮哨兵划分后右子数组长度为 $0$ ,递归树的高度会达到 $n - 1$ ,此时需要占用 $O(n)$ 大小的栈帧空间。 -为了防止栈帧空间的累积,我们可以在每轮哨兵排序完成后,比较两个子数组的长度,**仅对较短的子数组进行递归**。由于较短子数组的长度不会超过 $\frac{n}{2}$ ,因此这种方法能确保递归深度不超过 $\log n$ ,从而将最差空间复杂度优化至 $O(\log n)$ 。 +为了防止栈帧空间的累积,我们可以在每轮哨兵排序完成后,比较两个子数组的长度,**仅对较短的子数组进行递归**。由于较短子数组的长度不会超过 $n / 2$ ,因此这种方法能确保递归深度不超过 $\log n$ ,从而将最差空间复杂度优化至 $O(\log n)$ 。 === "Java" diff --git a/docs/chapter_tree/binary_tree_traversal.md b/docs/chapter_tree/binary_tree_traversal.md index e10cdd7cf..72ee77ccf 100755 --- a/docs/chapter_tree/binary_tree_traversal.md +++ b/docs/chapter_tree/binary_tree_traversal.md @@ -88,7 +88,7 @@ **时间复杂度**:所有节点被访问一次,使用 $O(n)$ 时间,其中 $n$ 为节点数量。 -**空间复杂度**:在最差情况下,即满二叉树时,遍历到最底层之前,队列中最多同时存在 $\frac{n + 1}{2}$ 个节点,占用 $O(n)$ 空间。 +**空间复杂度**:在最差情况下,即满二叉树时,遍历到最底层之前,队列中最多同时存在 $(n + 1) / 2$ 个节点,占用 $O(n)$ 空间。 ## 前序、中序、后序遍历