diff --git a/codes/c/chapter_stack_and_queue/array_stack.c b/codes/c/chapter_stack_and_queue/array_stack.c
index 807c9bca4..39e1cff4d 100644
--- a/codes/c/chapter_stack_and_queue/array_stack.c
+++ b/codes/c/chapter_stack_and_queue/array_stack.c
@@ -90,11 +90,11 @@ int main() {
/* 获取栈的长度 */
int size = stack->size;
- printf("栈的长度 size = %d\n", size);
+ printf("栈的长度 size = %d\n", size);
/* 判断是否为空 */
bool empty = isEmpty(stack);
- printf("栈是否为空 = %stack\n", empty ? "true" : "false");
+ printf("栈是否为空 = %s\n", empty ? "true" : "false");
// 释放内存
delArrayStack(stack);
diff --git a/codes/kotlin/chapter_sorting/merge_sort.kt b/codes/kotlin/chapter_sorting/merge_sort.kt
index 40ca9ca97..d08d3d925 100644
--- a/codes/kotlin/chapter_sorting/merge_sort.kt
+++ b/codes/kotlin/chapter_sorting/merge_sort.kt
@@ -19,7 +19,7 @@ fun merge(nums: IntArray, left: Int, mid: Int, right: Int) {
while (i <= mid && j <= right) {
if (nums[i] <= nums[j])
tmp[k++] = nums[i++]
- else
+ else
tmp[k++] = nums[j++]
}
// 将左子数组和右子数组的剩余元素复制到临时数组中
diff --git a/codes/python/chapter_computational_complexity/time_complexity.py b/codes/python/chapter_computational_complexity/time_complexity.py
index ac404c831..5e25f2798 100644
--- a/codes/python/chapter_computational_complexity/time_complexity.py
+++ b/codes/python/chapter_computational_complexity/time_complexity.py
@@ -97,7 +97,9 @@ def linear_log_recur(n: int) -> int:
"""线性对数阶"""
if n <= 1:
return 1
- count: int = linear_log_recur(n // 2) + linear_log_recur(n // 2)
+ # 一分为二,子问题的规模减小一半
+ count = linear_log_recur(n // 2) + linear_log_recur(n // 2)
+ # 当前子问题包含 n 个操作
for _ in range(n):
count += 1
return count
@@ -120,32 +122,32 @@ if __name__ == "__main__":
n = 8
print("输入数据大小 n =", n)
- count: int = constant(n)
+ count = constant(n)
print("常数阶的操作数量 =", count)
- count: int = linear(n)
+ count = linear(n)
print("线性阶的操作数量 =", count)
- count: int = array_traversal([0] * n)
+ count = array_traversal([0] * n)
print("线性阶(遍历数组)的操作数量 =", count)
- count: int = quadratic(n)
+ count = quadratic(n)
print("平方阶的操作数量 =", count)
nums = [i for i in range(n, 0, -1)] # [n, n-1, ..., 2, 1]
- count: int = bubble_sort(nums)
+ count = bubble_sort(nums)
print("平方阶(冒泡排序)的操作数量 =", count)
- count: int = exponential(n)
+ count = exponential(n)
print("指数阶(循环实现)的操作数量 =", count)
- count: int = exp_recur(n)
+ count = exp_recur(n)
print("指数阶(递归实现)的操作数量 =", count)
- count: int = logarithmic(n)
+ count = logarithmic(n)
print("对数阶(循环实现)的操作数量 =", count)
- count: int = log_recur(n)
+ count = log_recur(n)
print("对数阶(递归实现)的操作数量 =", count)
- count: int = linear_log_recur(n)
+ count = linear_log_recur(n)
print("线性对数阶(递归实现)的操作数量 =", count)
- count: int = factorial_recur(n)
+ count = factorial_recur(n)
print("阶乘阶(递归实现)的操作数量 =", count)
diff --git a/codes/ruby/chapter_dynamic_programming/climbing_stairs_constraint_dp.rb b/codes/ruby/chapter_dynamic_programming/climbing_stairs_constraint_dp.rb
index 1421d09f5..4d6bf065f 100644
--- a/codes/ruby/chapter_dynamic_programming/climbing_stairs_constraint_dp.rb
+++ b/codes/ruby/chapter_dynamic_programming/climbing_stairs_constraint_dp.rb
@@ -5,7 +5,7 @@ Author: Xuan Khoa Tu Nguyen (ngxktuzkai2000@gmail.com)
=end
### 带约束爬楼梯:动态规划 ###
-def climbing_stairs_backtrack(n)
+def climbing_stairs_constraint_dp(n)
return 1 if n == 1 || n == 2
# 初始化 dp 表,用于存储子问题的解
@@ -26,6 +26,6 @@ end
if __FILE__ == $0
n = 9
- res = climbing_stairs_backtrack(n)
+ res = climbing_stairs_constraint_dp(n)
puts "爬 #{n} 阶楼梯共有 #{res} 种方案"
end
diff --git a/docs/assets/avatar/avatar_khoaxuantu.jpg b/docs/assets/avatar/avatar_khoaxuantu.jpg
new file mode 100644
index 000000000..f7e1e8f3c
Binary files /dev/null and b/docs/assets/avatar/avatar_khoaxuantu.jpg differ
diff --git a/docs/chapter_array_and_linkedlist/summary.md b/docs/chapter_array_and_linkedlist/summary.md
index 522d055d0..9a42b3df1 100644
--- a/docs/chapter_array_and_linkedlist/summary.md
+++ b/docs/chapter_array_and_linkedlist/summary.md
@@ -73,4 +73,4 @@
**Q**:初始化列表 `res = [0] * self.size()` 操作,会导致 `res` 的每个元素引用相同的地址吗?
-不会。但二维数组会有这个问题,例如初始化二维列表 `res = [[0] * self.size()]` ,则多次引用了同一个列表 `[0]` 。
+不会。但二维数组会有这个问题,例如初始化二维列表 `res = [[0]] * self.size()` ,则多次引用了同一个列表 `[0]` 。
diff --git a/docs/chapter_computational_complexity/performance_evaluation.md b/docs/chapter_computational_complexity/performance_evaluation.md
index 3c286d0be..8ede9795a 100644
--- a/docs/chapter_computational_complexity/performance_evaluation.md
+++ b/docs/chapter_computational_complexity/performance_evaluation.md
@@ -7,7 +7,7 @@
也就是说,在能够解决问题的前提下,算法效率已成为衡量算法优劣的主要评价指标,它包括以下两个维度。
-- **时间效率**:算法运行速度的快慢。
+- **时间效率**:算法运行时间的长短。
- **空间效率**:算法占用内存空间的大小。
简而言之,**我们的目标是设计“既快又省”的数据结构与算法**。而有效地评估算法效率至关重要,因为只有这样,我们才能将各种算法进行对比,进而指导算法设计与优化过程。
@@ -18,7 +18,7 @@
假设我们现在有算法 `A` 和算法 `B` ,它们都能解决同一问题,现在需要对比这两个算法的效率。最直接的方法是找一台计算机,运行这两个算法,并监控记录它们的运行时间和内存占用情况。这种评估方式能够反映真实情况,但也存在较大的局限性。
-一方面,**难以排除测试环境的干扰因素**。硬件配置会影响算法的性能。比如在某台计算机中,算法 `A` 的运行时间比算法 `B` 短;但在另一台配置不同的计算机中,可能得到相反的测试结果。这意味着我们需要在各种机器上进行测试,统计平均效率,而这是不现实的。
+一方面,**难以排除测试环境的干扰因素**。硬件配置会影响算法的性能表现。比如一个算法的并行度较高,那么它就更适合在多核 CPU 上运行,一个算法的内存操作密集,那么它在高性能内存上的表现就会更好。也就是说,算法在不同的机器上的测试结果可能是不一致的。这意味着我们需要在各种机器上进行测试,统计平均效率,而这是不现实的。
另一方面,**展开完整测试非常耗费资源**。随着输入数据量的变化,算法会表现出不同的效率。例如,在输入数据量较小时,算法 `A` 的运行时间比算法 `B` 短;而在输入数据量较大时,测试结果可能恰恰相反。因此,为了得到有说服力的结论,我们需要测试各种规模的输入数据,而这需要耗费大量的计算资源。
@@ -32,8 +32,9 @@
- “随着输入数据大小的增加”意味着复杂度反映了算法运行效率与输入数据体量之间的关系。
- “时间和空间的增长趋势”表示复杂度分析关注的不是运行时间或占用空间的具体值,而是时间或空间增长的“快慢”。
-**复杂度分析克服了实际测试方法的弊端**,体现在以下两个方面。
+**复杂度分析克服了实际测试方法的弊端**,体现在以下几个方面。
+- 它无需实际运行代码,更加绿色节能。
- 它独立于测试环境,分析结果适用于所有运行平台。
- 它可以体现不同数据量下的算法效率,尤其是在大数据量下的算法性能。
diff --git a/docs/chapter_computational_complexity/time_complexity.md b/docs/chapter_computational_complexity/time_complexity.md
index c02f91443..325571494 100755
--- a/docs/chapter_computational_complexity/time_complexity.md
+++ b/docs/chapter_computational_complexity/time_complexity.md
@@ -534,7 +534,7 @@ $$
- **时间复杂度能够有效评估算法效率**。例如,算法 `B` 的运行时间呈线性增长,在 $n > 1$ 时比算法 `A` 更慢,在 $n > 1000000$ 时比算法 `C` 更慢。事实上,只要输入数据大小 $n$ 足够大,复杂度为“常数阶”的算法一定优于“线性阶”的算法,这正是时间增长趋势的含义。
- **时间复杂度的推算方法更简便**。显然,运行平台和计算操作类型都与算法运行时间的增长趋势无关。因此在时间复杂度分析中,我们可以简单地将所有计算操作的执行时间视为相同的“单位时间”,从而将“计算操作运行时间统计”简化为“计算操作数量统计”,这样一来估算难度就大大降低了。
-- **时间复杂度也存在一定的局限性**。例如,尽管算法 `A` 和 `C` 的时间复杂度相同,但实际运行时间差别很大。同样,尽管算法 `B` 的时间复杂度比 `C` 高,但在输入数据大小 $n$ 较小时,算法 `B` 明显优于算法 `C` 。在这些情况下,我们很难仅凭时间复杂度判断算法效率的高低。当然,尽管存在上述问题,复杂度分析仍然是评判算法效率最有效且常用的方法。
+- **时间复杂度也存在一定的局限性**。例如,尽管算法 `A` 和 `C` 的时间复杂度相同,但实际运行时间差别很大。同样,尽管算法 `B` 的时间复杂度比 `C` 高,但在输入数据大小 $n$ 较小时,算法 `B` 明显优于算法 `C` 。对于此类情况,我们时常难以仅凭时间复杂度判断算法效率的高低。当然,尽管存在上述问题,复杂度分析仍然是评判算法效率最有效且常用的方法。
## 函数渐近上界
diff --git a/docs/chapter_data_structure/summary.md b/docs/chapter_data_structure/summary.md
index 38425fa46..54af46600 100644
--- a/docs/chapter_data_structure/summary.md
+++ b/docs/chapter_data_structure/summary.md
@@ -35,7 +35,7 @@
**Q**:原码转补码的方法是“先取反后加 1”,那么补码转原码应该是逆运算“先减 1 后取反”,而补码转原码也一样可以通过“先取反后加 1”得到,这是为什么呢?
-**A**:这是因为原码和补码的相互转换实际上是计算“补数”的过程。我们先给出补数的定义:假设 $a + b = c$ ,那么我们称 $a$ 是 $b$ 到 $c$ 的补数,反之也称 $b$ 是 $a$ 到 $c$ 的补数。
+这是因为原码和补码的相互转换实际上是计算“补数”的过程。我们先给出补数的定义:假设 $a + b = c$ ,那么我们称 $a$ 是 $b$ 到 $c$ 的补数,反之也称 $b$ 是 $a$ 到 $c$ 的补数。
给定一个 $n = 4$ 位长度的二进制数 $0010$ ,如果将这个数字看作原码(不考虑符号位),那么它的补码需通过“先取反后加 1”得到:
@@ -63,4 +63,4 @@ $$
本质上看,“取反”操作实际上是求到 $1111$ 的补数(因为恒有 `原码 + 反码 = 1111`);而在反码基础上再加 1 得到的补码,就是到 $10000$ 的补数。
-上述 $n = 4$ 为例,其可推广至任意位数的二进制数。
+上述以 $n = 4$ 为例,其可被推广至任意位数的二进制数。
diff --git a/docs/chapter_introduction/what_is_dsa.md b/docs/chapter_introduction/what_is_dsa.md
index 953a79b7f..9bc5e0d5a 100644
--- a/docs/chapter_introduction/what_is_dsa.md
+++ b/docs/chapter_introduction/what_is_dsa.md
@@ -10,7 +10,7 @@
## 数据结构定义
-数据结构(data structure)是计算机中组织和存储数据的方式,具有以下设计目标。
+数据结构(data structure)是组织和存储数据的方式,涵盖数据内容、数据之间关系和数据操作方法,它具有以下设计目标。
- 空间占用尽量少,以节省计算机内存。
- 数据操作尽可能快速,涵盖数据访问、添加、删除、更新等。
diff --git a/docs/index.html b/docs/index.html
index 9726d5b33..965774d9a 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -322,6 +322,13 @@
JS, TS
+