From 4bc6b8af7b238d100cfaf6c76c21d3e5917e07ff Mon Sep 17 00:00:00 2001 From: krahets Date: Sun, 6 Aug 2023 23:19:37 +0800 Subject: [PATCH] finetune --- .../binary_search_insertion.cpp | 2 +- docs/chapter_array_and_linkedlist/array.md | 4 ++-- .../linked_list.md | 20 ++++++++----------- docs/chapter_array_and_linkedlist/list.md | 6 +++--- .../summary.md | 13 +++++++----- docs/chapter_heap/heap.md | 2 +- docs/chapter_searching/binary_search_edge.md | 2 +- docs/chapter_stack_and_queue/stack.md | 2 +- 8 files changed, 25 insertions(+), 26 deletions(-) diff --git a/codes/cpp/chapter_searching/binary_search_insertion.cpp b/codes/cpp/chapter_searching/binary_search_insertion.cpp index a5e1a178f..4df59f2be 100644 --- a/codes/cpp/chapter_searching/binary_search_insertion.cpp +++ b/codes/cpp/chapter_searching/binary_search_insertion.cpp @@ -1,5 +1,5 @@ /** - * File: binary_search_edge.cpp + * File: binary_search_insertion.cpp * Created Time: 2023-08-04 * Author: Krahets (krahets@163.com) */ diff --git a/docs/chapter_array_and_linkedlist/array.md b/docs/chapter_array_and_linkedlist/array.md index b271eaf53..9b41e9255 100755 --- a/docs/chapter_array_and_linkedlist/array.md +++ b/docs/chapter_array_and_linkedlist/array.md @@ -30,8 +30,8 @@ ```python title="array.py" # 初始化数组 - arr: List[int] = [0] * 5 # [ 0, 0, 0, 0, 0 ] - nums: List[int] = [1, 3, 2, 5, 4] + arr: list[int] = [0] * 5 # [ 0, 0, 0, 0, 0 ] + nums: list[int] = [1, 3, 2, 5, 4] ``` === "Go" diff --git a/docs/chapter_array_and_linkedlist/linked_list.md b/docs/chapter_array_and_linkedlist/linked_list.md index bb5c7081c..6d50f3efa 100755 --- a/docs/chapter_array_and_linkedlist/linked_list.md +++ b/docs/chapter_array_and_linkedlist/linked_list.md @@ -1,10 +1,10 @@ # 链表 -内存空间是所有程序的公共资源,排除已被占用的内存空间,空闲内存空间通常散落在内存各处。在上一节中,我们提到存储数组的内存空间必须是连续的,而当我们需要申请一个非常大的数组时,空闲内存中可能没有这么大的连续空间。与数组相比,链表更具灵活性,它可以被存储在非连续的内存空间中。 +内存空间是所有程序的公共资源,排除已被占用的内存空间,空闲内存空间通常散落在内存各处。在上一节中,我们提到存储数组的内存空间必须是连续的,而当需要申请一个非常大的数组时,空闲内存中可能没有这么大的连续空间。与数组相比,链表更具灵活性,它可以被存储在非连续的内存空间中。 「链表 Linked List」是一种线性数据结构,其每个元素都是一个节点对象,各个节点之间通过指针连接,从当前节点通过指针可以访问到下一个节点。**由于指针记录了下个节点的内存地址,因此无需保证内存地址的连续性**,从而可以将各个节点分散存储在内存各处。 -链表「节点 Node」包含两项数据,一是节点「值 Value」,二是指向下一节点的「指针 Pointer」,或称「引用 Reference」。 +链表中的「节点 Node」包含两项数据,一是节点「值 Value」,二是指向下一节点的「指针 Pointer」,或称「引用 Reference」。 ![链表定义与存储方式](linked_list.assets/linkedlist_definition.png) @@ -169,13 +169,7 @@ ``` -!!! question "尾节点指向什么?" - - 我们将链表的最后一个节点称为「尾节点」,其指向的是“空”,在 Java, C++, Python 中分别记为 $\text{null}$ , $\text{nullptr}$ , $\text{None}$ 。在不引起歧义的前提下,本书都使用 $\text{None}$ 来表示空。 - -!!! question "如何称呼链表?" - - 在编程语言中,数组整体就是一个变量,例如数组 `nums` ,包含各个元素 `nums[0]` , `nums[1]` 等等。而链表是由多个节点对象组成,我们通常将头节点当作链表的代称,例如头节点 `head` 和链表 `head` 实际上是同义的。 +我们将链表的首个节点称为「头节点」,最后一个节点称为「尾节点」。尾节点指向的是“空”,在 Java, C++, Python 中分别记为 $\text{null}$ , $\text{nullptr}$ , $\text{None}$ 。在不引起歧义的前提下,本书都使用 $\text{None}$ 来表示空。 **链表初始化方法**。建立链表分为两步,第一步是初始化各个节点对象,第二步是构建引用指向关系。完成后,即可以从链表的头节点(即首个节点)出发,通过指针 `next` 依次访问所有节点。 @@ -372,9 +366,11 @@ ``` +在编程语言中,数组整体是一个变量,比如数组 `nums` 包含元素 `nums[0]` , `nums[1]` 等。而链表是由多个分散的节点对象组成,**我们通常将头节点当作链表的代称**,比如以上代码中的链表可被记做链表 `n0` 。 + ## 链表优点 -**链表中插入与删除节点的操作效率高**。例如,如果我们想在链表中间的两个节点 `A` , `B` 之间插入一个新节点 `P` ,我们只需要改变两个节点指针即可,时间复杂度为 $O(1)$ ;相比之下,数组的插入操作效率要低得多。 +**链表中插入与删除节点的操作效率高**。如果我们想在链表中间的两个节点 `A` , `B` 之间插入一个新节点 `P` ,我们只需要改变两个节点指针即可,时间复杂度为 $O(1)$ ;相比之下,数组的插入操作效率要低得多。 ![链表插入节点](linked_list.assets/linkedlist_insert_node.png) @@ -528,7 +524,7 @@ ## 链表缺点 -**链表访问节点效率较低**。如上节所述,数组可以在 $O(1)$ 时间下访问任意元素。然而,链表无法直接访问任意节点,这是因为系统需要从头节点出发,逐个向后遍历直至找到目标节点。例如,若要访问链表索引为 `index`(即第 `index + 1` 个)的节点,则需要向后遍历 `index` 轮。 +**链表访问节点效率较低**。如上节所述,数组可以在 $O(1)$ 时间下访问任意元素。然而链表无法直接访问任意节点,因为程序需要从头节点出发,逐个向后遍历,直至找到目标节点。也就是说,如果想要访问链表中第 $i$ 个节点,则需要向后遍历 $i - 1$ 轮。 === "Java" @@ -602,7 +598,7 @@ [class]{}-[func]{access} ``` -**链表的内存占用较大**。链表以节点为单位,每个节点除了保存值之外,还需额外保存指针(引用)。这意味着在相同数据量的情况下,链表比数组需要占用更多的内存空间。 +**链表的内存占用较大**。链表以节点为单位,每个节点除了包含值,还需额外保存下一节点的引用(指针)。这意味着在相同数据量的情况下,链表比数组需要占用更多的内存空间。 ## 链表常用操作 diff --git a/docs/chapter_array_and_linkedlist/list.md b/docs/chapter_array_and_linkedlist/list.md index 00335f125..028097c17 100755 --- a/docs/chapter_array_and_linkedlist/list.md +++ b/docs/chapter_array_and_linkedlist/list.md @@ -35,9 +35,9 @@ ```python title="list.py" # 初始化列表 # 无初始值 - list1: List[int] = [] + list1: list[int] = [] # 有初始值 - list: List[int] = [1, 3, 2, 5, 4] + list: list[int] = [1, 3, 2, 5, 4] ``` === "Go" @@ -646,7 +646,7 @@ ```python title="list.py" # 拼接两个列表 - list1: List[int] = [6, 8, 7, 10, 9] + list1: list[int] = [6, 8, 7, 10, 9] list += list1 # 将列表 list1 拼接到 list 之后 ``` diff --git a/docs/chapter_computational_complexity/summary.md b/docs/chapter_computational_complexity/summary.md index 20ea33f85..efda91ea1 100644 --- a/docs/chapter_computational_complexity/summary.md +++ b/docs/chapter_computational_complexity/summary.md @@ -26,17 +26,20 @@ !!! question "尾递归的空间复杂度是 $O(1)$ 吗?" - 理论上,尾递归函数的空间复杂度可以被优化至 $O(1)$ 。不过绝大多数编程语言(例如 Java, Python, C++, Go, C# 等) - 都不支持自动优化尾递归,因此一般来说空间复杂度是 $O(n)$ 。 + 理论上,尾递归函数的空间复杂度可以被优化至 $O(1)$ 。不过绝大多数编程语言(例如 Java, Python, C++, Go, C# 等)都不支持自动优化尾递归,因此通常认为空间复杂度是 $O(n)$ 。 !!! question "函数和方法这两个术语的区别是什么?" - 函数(function)可以独立被执行,所有参数都以显式传递。 - 方法(method)与一个对象关联,方法被隐式传递给调用它的对象,方法能够对类的实例中包含的数据进行操作。 + 函数(function)可以独立被执行,所有参数都以显式传递。方法(method)与一个对象关联,方法被隐式传递给调用它的对象,方法能够对类的实例中包含的数据进行操作。 - 因此,C 和 Go 只有函数,Java 和 C# 只有方法,在 C++, Python 中取决于它是否属于一个类。 + 以几个常见的编程语言为例: + + - C 语言是过程式编程语言,没有面向对象的概念,所以只有函数。但我们可以通过创建结构(struct)来模拟面向对象编程,与结构体相关联的函数就相当于其他语言中的方法。 + - Java, C# 是面向对象的编程语言,代码块(方法)通常都是作为某个类的一部分。静态方法的行为类似于函数,因为它被绑定在类上,不能访问特定的实例变量。 + - C++, Python 既支持过程式编程(函数)也支持面向对象编程(方法)。 !!! question "图片“空间复杂度的常见类型”反映的是否是占用空间的绝对大小?" 不是,该图片展示的是空间复杂度(即增长趋势),而不是占用空间的绝对大小。每个曲线都包含一个常数项,用来把所有曲线的取值范围压缩到一个视觉舒适的范围内。 + 实际中,因为我们通常不知道每个方法的“常数项”复杂度是多少,所以一般无法仅凭复杂度来选择 $n = 8$ 之下的最优解法;但相对地 $n = 8^5$ 就很好选了,这是复杂度占主导的情况。 diff --git a/docs/chapter_heap/heap.md b/docs/chapter_heap/heap.md index 816de192b..28b51cd7c 100644 --- a/docs/chapter_heap/heap.md +++ b/docs/chapter_heap/heap.md @@ -151,7 +151,7 @@ is_empty: bool = not max_heap # 输入列表并建堆 - min_heap: List[int] = [1, 3, 2, 5, 4] + min_heap: list[int] = [1, 3, 2, 5, 4] heapq.heapify(min_heap) ``` diff --git a/docs/chapter_searching/binary_search_edge.md b/docs/chapter_searching/binary_search_edge.md index 4641efa29..0f550f9a4 100644 --- a/docs/chapter_searching/binary_search_edge.md +++ b/docs/chapter_searching/binary_search_edge.md @@ -6,7 +6,7 @@ 给定一个长度为 $n$ 的有序数组 `nums` ,数组可能包含重复元素。请返回数组中最左一个元素 `target` 的索引。若数组中不包含该元素,则返回 $-1$ 。 -回忆二分查找插入点的方法,搜索完成后,$i$ 指向最左一个 `target` ,**因此查找插入点本质上是在查找最左一个 `target` 的索引**。 +回忆二分查找插入点的方法,搜索完成后 $i$ 指向最左一个 `target` ,**因此查找插入点本质上是在查找最左一个 `target` 的索引**。 考虑通过查找插入点的函数实现查找左边界。请注意,数组中可能不包含 `target` ,此时有两种可能: diff --git a/docs/chapter_stack_and_queue/stack.md b/docs/chapter_stack_and_queue/stack.md index 75148940f..703954e50 100755 --- a/docs/chapter_stack_and_queue/stack.md +++ b/docs/chapter_stack_and_queue/stack.md @@ -81,7 +81,7 @@ ```python title="stack.py" # 初始化栈 # Python 没有内置的栈类,可以把 List 当作栈来使用 - stack: List[int] = [] + stack: list[int] = [] # 元素入栈 stack.append(1)