diff --git a/chapter_appendix/contribution.assets/edit_markdown.png b/chapter_appendix/contribution.assets/edit_markdown.png index 032e5d109..f2becc22d 100644 Binary files a/chapter_appendix/contribution.assets/edit_markdown.png and b/chapter_appendix/contribution.assets/edit_markdown.png differ diff --git a/chapter_array_and_linkedlist/array.assets/array_definition.png b/chapter_array_and_linkedlist/array.assets/array_definition.png index 240cbac81..4a1c32c25 100644 Binary files a/chapter_array_and_linkedlist/array.assets/array_definition.png and b/chapter_array_and_linkedlist/array.assets/array_definition.png differ diff --git a/chapter_array_and_linkedlist/array.assets/array_insert_element.png b/chapter_array_and_linkedlist/array.assets/array_insert_element.png index b286f05a3..77e0eaf4f 100644 Binary files a/chapter_array_and_linkedlist/array.assets/array_insert_element.png and b/chapter_array_and_linkedlist/array.assets/array_insert_element.png differ diff --git a/chapter_array_and_linkedlist/array.assets/array_memory_location_calculation.png b/chapter_array_and_linkedlist/array.assets/array_memory_location_calculation.png index 7514ee187..3f848d832 100644 Binary files a/chapter_array_and_linkedlist/array.assets/array_memory_location_calculation.png and b/chapter_array_and_linkedlist/array.assets/array_memory_location_calculation.png differ diff --git a/chapter_array_and_linkedlist/array.assets/array_remove_element.png b/chapter_array_and_linkedlist/array.assets/array_remove_element.png index e2e9210c7..516d58531 100644 Binary files a/chapter_array_and_linkedlist/array.assets/array_remove_element.png and b/chapter_array_and_linkedlist/array.assets/array_remove_element.png differ diff --git a/chapter_array_and_linkedlist/linked_list.assets/linkedlist_common_types.png b/chapter_array_and_linkedlist/linked_list.assets/linkedlist_common_types.png index 773205521..df5d08422 100644 Binary files a/chapter_array_and_linkedlist/linked_list.assets/linkedlist_common_types.png and b/chapter_array_and_linkedlist/linked_list.assets/linkedlist_common_types.png differ diff --git a/chapter_array_and_linkedlist/linked_list.assets/linkedlist_definition.png b/chapter_array_and_linkedlist/linked_list.assets/linkedlist_definition.png index 0a37934b1..ea7d12cf1 100644 Binary files a/chapter_array_and_linkedlist/linked_list.assets/linkedlist_definition.png and b/chapter_array_and_linkedlist/linked_list.assets/linkedlist_definition.png differ diff --git a/chapter_array_and_linkedlist/linked_list.assets/linkedlist_insert_node.png b/chapter_array_and_linkedlist/linked_list.assets/linkedlist_insert_node.png index 25758896c..be04c6981 100644 Binary files a/chapter_array_and_linkedlist/linked_list.assets/linkedlist_insert_node.png and b/chapter_array_and_linkedlist/linked_list.assets/linkedlist_insert_node.png differ diff --git a/chapter_array_and_linkedlist/linked_list.assets/linkedlist_remove_node.png b/chapter_array_and_linkedlist/linked_list.assets/linkedlist_remove_node.png index 542ea8d7a..f1383a00c 100644 Binary files a/chapter_array_and_linkedlist/linked_list.assets/linkedlist_remove_node.png and b/chapter_array_and_linkedlist/linked_list.assets/linkedlist_remove_node.png differ diff --git a/chapter_array_and_linkedlist/linked_list/index.html b/chapter_array_and_linkedlist/linked_list/index.html index fda72c659..abb34950d 100644 --- a/chapter_array_and_linkedlist/linked_list/index.html +++ b/chapter_array_and_linkedlist/linked_list/index.html @@ -1769,44 +1769,44 @@
内存空间是所有程序的公共资源,排除已被占用的内存空间,空闲内存空间通常散落在内存各处。在上一节中,我们提到存储数组的内存空间必须是连续的,而当我们需要申请一个非常大的数组时,空闲内存中可能没有这么大的连续空间。
-与数组相比,链表更具灵活性,因为它可以存储在非连续的内存空间。「链表 Linked List」是一种线性数据结构,其每个元素都是一个结点对象,各个结点之间通过指针连接,从当前结点通过指针可以访问到下一个结点。由于指针记录了下个结点的内存地址,因此无需保证内存地址的连续性,从而可以将各个结点分散存储在内存各处。
-链表「结点 Node」包含两项数据,一是结点「值 Value」,二是指向下一结点的「指针 Pointer」,或称指向下一结点的「引用 Reference」。
+与数组相比,链表更具灵活性,因为它可以存储在非连续的内存空间。「链表 Linked List」是一种线性数据结构,其每个元素都是一个节点对象,各个节点之间通过指针连接,从当前节点通过指针可以访问到下一个节点。由于指针记录了下个节点的内存地址,因此无需保证内存地址的连续性,从而可以将各个节点分散存储在内存各处。
+链表「节点 Node」包含两项数据,一是节点「值 Value」,二是指向下一节点的「指针 Pointer」,或称指向下一节点的「引用 Reference」。

Fig. 链表定义与存储方式
/* 链表结点类 */
+/* 链表节点类 */
class ListNode {
val: number;
next: ListNode | null;
constructor(val?: number, next?: ListNode | null) {
- this.val = val === undefined ? 0 : val; // 结点值
- this.next = next === undefined ? null : next; // 指向下一结点的引用
+ this.val = val === undefined ? 0 : val; // 节点值
+ this.next = next === undefined ? null : next; // 指向下一节点的引用
}
}
/* 链表结点结构体 */
+/* 链表节点结构体 */
struct ListNode {
- int val; // 结点值
- struct ListNode *next; // 指向下一结点的指针(引用)
+ int val; // 节点值
+ struct ListNode *next; // 指向下一节点的指针(引用)
};
// typedef 作用是为一种数据类型定义一个新名字
typedef struct ListNode ListNode;
-/* 构造函数,初始化一个新结点 */
+/* 构造函数,初始化一个新节点 */
ListNode *newListNode(int val) {
ListNode *node, *next;
node = (ListNode *) malloc(sizeof(ListNode));
@@ -1863,20 +1863,20 @@
尾结点指向什么?
-我们将链表的最后一个结点称为「尾结点」,其指向的是“空”,在 Java, C++, Python 中分别记为 null, nullptr, None 。在不引起歧义的前提下,本书都使用 null 来表示空。
尾节点指向什么?
+我们将链表的最后一个节点称为「尾节点」,其指向的是“空”,在 Java, C++, Python 中分别记为 null, nullptr, None 。在不引起歧义的前提下,本书都使用 null 来表示空。
如何称呼链表?
-在编程语言中,数组整体就是一个变量,例如数组 nums ,包含各个元素 nums[0] , nums[1] 等等。而链表是由多个结点对象组成,我们通常将头结点当作链表的代称,例如头结点 head 和链表 head 实际上是同义的。
在编程语言中,数组整体就是一个变量,例如数组 nums ,包含各个元素 nums[0] , nums[1] 等等。而链表是由多个节点对象组成,我们通常将头节点当作链表的代称,例如头节点 head 和链表 head 实际上是同义的。
链表初始化方法。建立链表分为两步,第一步是初始化各个结点对象,第二步是构建引用指向关系。完成后,即可以从链表的头结点(即首个结点)出发,通过指针 next 依次访问所有结点。
链表初始化方法。建立链表分为两步,第一步是初始化各个节点对象,第二步是构建引用指向关系。完成后,即可以从链表的头节点(即首个节点)出发,通过指针 next 依次访问所有节点。
/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
-// 初始化各个结点
+// 初始化各个节点
ListNode n0 = new ListNode(1);
ListNode n1 = new ListNode(3);
ListNode n2 = new ListNode(2);
@@ -1932,7 +1932,7 @@
/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
-// 初始化各个结点
+// 初始化各个节点
ListNode* n0 = new ListNode(1);
ListNode* n1 = new ListNode(3);
ListNode* n2 = new ListNode(2);
@@ -1947,7 +1947,7 @@
""" 初始化链表 1 -> 3 -> 2 -> 5 -> 4 """
-# 初始化各个结点
+# 初始化各个节点
n0 = ListNode(1)
n1 = ListNode(3)
n2 = ListNode(2)
@@ -1962,7 +1962,7 @@
/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
-// 初始化各个结点
+// 初始化各个节点
n0 := NewListNode(1)
n1 := NewListNode(3)
n2 := NewListNode(2)
@@ -1977,7 +1977,7 @@
/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
-// 初始化各个结点
+// 初始化各个节点
const n0 = new ListNode(1);
const n1 = new ListNode(3);
const n2 = new ListNode(2);
@@ -1992,7 +1992,7 @@
/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
-// 初始化各个结点
+// 初始化各个节点
const n0 = new ListNode(1);
const n1 = new ListNode(3);
const n2 = new ListNode(2);
@@ -2007,7 +2007,7 @@
/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
-// 初始化各个结点
+// 初始化各个节点
ListNode* n0 = newListNode(1);
ListNode* n1 = newListNode(3);
ListNode* n2 = newListNode(2);
@@ -2022,7 +2022,7 @@
/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
-// 初始化各个结点
+// 初始化各个节点
ListNode n0 = new ListNode(1);
ListNode n1 = new ListNode(3);
ListNode n2 = new ListNode(2);
@@ -2037,7 +2037,7 @@
/* 初始化链表 1 -> 3 -> 2 -> 5 -> 4 */
-// 初始化各个结点
+// 初始化各个节点
let n0 = ListNode(x: 1)
let n1 = ListNode(x: 3)
let n2 = ListNode(x: 2)
@@ -2052,7 +2052,7 @@
链表中插入与删除结点的操作效率高。例如,如果我们想在链表中间的两个结点 A , B 之间插入一个新结点 P ,我们只需要改变两个结点指针即可,时间复杂度为 \(O(1)\) ;相比之下,数组的插入操作效率要低得多。

Fig. 链表插入结点
+链表中插入与删除节点的操作效率高。例如,如果我们想在链表中间的两个节点 A , B 之间插入一个新节点 P ,我们只需要改变两个节点指针即可,时间复杂度为 \(O(1)\) ;相比之下,数组的插入操作效率要低得多。

Fig. 链表插入节点
/* 在链表的结点 n0 之后插入结点 P */
+linked_list.cpp/* 在链表的节点 n0 之后插入节点 P */
void insert(ListNode* n0, ListNode* P) {
ListNode* n1 = n0->next;
P->next = n1;
@@ -2094,14 +2094,14 @@
-
-
-
-
-
-
-在链表中删除结点也非常方便,只需改变一个结点的指针即可。如下图所示,尽管在删除操作完成后,结点 P 仍然指向 n1,但实际上 P 已经不再属于此链表,因为遍历此链表时无法访问到 P。
-
- Fig. 链表删除结点
+在链表中删除节点也非常方便,只需改变一个节点的指针即可。如下图所示,尽管在删除操作完成后,节点 P 仍然指向 n1,但实际上 P 已经不再属于此链表,因为遍历此链表时无法访问到 P。
+
+ Fig. 链表删除节点
-
-linked_list.cpp/* 删除链表的结点 n0 之后的首个结点 */
+linked_list.cpp/* 删除链表的节点 n0 之后的首个节点 */
void remove(ListNode* n0) {
if (n0->next == nullptr)
return;
@@ -2195,7 +2195,7 @@
-
-
-
-
-
-
4.2.2. 链表缺点¶
-链表访问结点效率较低。如上节所述,数组可以在 \(O(1)\) 时间下访问任意元素。然而,链表无法直接访问任意结点,这是因为系统需要从头结点出发,逐个向后遍历直至找到目标结点。例如,若要访问链表索引为 index(即第 index + 1 个)的结点,则需要向后遍历 index 轮。
+链表访问节点效率较低。如上节所述,数组可以在 \(O(1)\) 时间下访问任意元素。然而,链表无法直接访问任意节点,这是因为系统需要从头节点出发,逐个向后遍历直至找到目标节点。例如,若要访问链表索引为 index(即第 index + 1 个)的节点,则需要向后遍历 index 轮。
-
-linked_list.cpp/* 访问链表中索引为 index 的结点 */
+linked_list.cpp/* 访问链表中索引为 index 的节点 */
ListNode* access(ListNode* head, int index) {
for (int i = 0; i < index; i++) {
if (head == nullptr)
@@ -2316,7 +2316,7 @@
-
-
-
-
-
-
-链表的内存占用较大。链表以结点为单位,每个结点除了保存值之外,还需额外保存指针(引用)。这意味着在相同数据量的情况下,链表比数组需要占用更多的内存空间。
+链表的内存占用较大。链表以节点为单位,每个节点除了保存值之外,还需额外保存指针(引用)。这意味着在相同数据量的情况下,链表比数组需要占用更多的内存空间。
4.2.3. 链表常用操作¶
-遍历链表查找。遍历链表,查找链表内值为 target 的结点,输出结点在链表中的索引。
+遍历链表查找。遍历链表,查找链表内值为 target 的节点,输出节点在链表中的索引。
-
-linked_list.cpp/* 在链表中查找值为 target 的首个结点 */
+linked_list.cpp/* 在链表中查找值为 target 的首个节点 */
int find(ListNode* head, int target) {
int index = 0;
while (head != nullptr) {
@@ -2445,7 +2445,7 @@
-
-
-
-
-
-
4.2.4. 常见链表类型¶
-单向链表。即上述介绍的普通链表。单向链表的结点包含值和指向下一结点的指针(引用)两项数据。我们将首个结点称为头结点,将最后一个结点成为尾结点,尾结点指向 null 。
-环形链表。如果我们令单向链表的尾结点指向头结点(即首尾相接),则得到一个环形链表。在环形链表中,任意结点都可以视作头结点。
-双向链表。与单向链表相比,双向链表记录了两个方向的指针(引用)。双向链表的结点定义同时包含指向后继结点(下一结点)和前驱结点(上一结点)的指针。相较于单向链表,双向链表更具灵活性,可以朝两个方向遍历链表,但相应地也需要占用更多的内存空间。
+单向链表。即上述介绍的普通链表。单向链表的节点包含值和指向下一节点的指针(引用)两项数据。我们将首个节点称为头节点,将最后一个节点成为尾节点,尾节点指向 null 。
+环形链表。如果我们令单向链表的尾节点指向头节点(即首尾相接),则得到一个环形链表。在环形链表中,任意节点都可以视作头节点。
+双向链表。与单向链表相比,双向链表记录了两个方向的指针(引用)。双向链表的节点定义同时包含指向后继节点(下一节点)和前驱节点(上一节点)的指针。相较于单向链表,双向链表更具灵活性,可以朝两个方向遍历链表,但相应地也需要占用更多的内存空间。
-
-
-""" 双向链表结点类 """
+""" 双向链表节点类 """
class ListNode:
def __init__(self, val: int):
- self.val: int = val # 结点值
- self.next: Optional[ListNode] = None # 指向后继结点的指针(引用)
- self.prev: Optional[ListNode] = None # 指向前驱结点的指针(引用)
+ self.val: int = val # 节点值
+ self.next: Optional[ListNode] = None # 指向后继节点的指针(引用)
+ self.prev: Optional[ListNode] = None # 指向前驱节点的指针(引用)
-
-/* 双向链表结点类 */
+/* 双向链表节点类 */
class ListNode {
val;
next;
prev;
constructor(val, next) {
- this.val = val === undefined ? 0 : val; // 结点值
- this.next = next === undefined ? null : next; // 指向后继结点的指针(引用)
- this.prev = prev === undefined ? null : prev; // 指向前驱结点的指针(引用)
+ this.val = val === undefined ? 0 : val; // 节点值
+ this.next = next === undefined ? null : next; // 指向后继节点的指针(引用)
+ this.prev = prev === undefined ? null : prev; // 指向前驱节点的指针(引用)
}
}
-/* 双向链表结点类 */
+/* 双向链表节点类 */
class ListNode {
val: number;
next: ListNode | null;
prev: ListNode | null;
constructor(val?: number, next?: ListNode | null, prev?: ListNode | null) {
- this.val = val === undefined ? 0 : val; // 结点值
- this.next = next === undefined ? null : next; // 指向后继结点的指针(引用)
- this.prev = prev === undefined ? null : prev; // 指向前驱结点的指针(引用)
+ this.val = val === undefined ? 0 : val; // 节点值
+ this.next = next === undefined ? null : next; // 指向后继节点的指针(引用)
+ this.prev = prev === undefined ? null : prev; // 指向前驱节点的指针(引用)
}
}
@@ -2638,21 +2638,21 @@
-
-
-// 双向链表结点类
+// 双向链表节点类
pub fn ListNode(comptime T: type) type {
return struct {
const Self = @This();
- val: T = 0, // 结点值
- next: ?*Self = null, // 指向后继结点的指针(引用)
- prev: ?*Self = null, // 指向前驱结点的指针(引用)
+ val: T = 0, // 节点值
+ next: ?*Self = null, // 指向后继节点的指针(引用)
+ prev: ?*Self = null, // 指向前驱节点的指针(引用)
// 构造函数
pub fn init(self: *Self, x: i32) void {
diff --git a/chapter_array_and_linkedlist/summary/index.html b/chapter_array_and_linkedlist/summary/index.html
index d22e40f19..db93e5bba 100644
--- a/chapter_array_and_linkedlist/summary/index.html
+++ b/chapter_array_and_linkedlist/summary/index.html
@@ -1683,7 +1683,7 @@
- 数组和链表是两种基本数据结构,分别代表数据在计算机内存中的连续空间存储和离散空间存储方式。两者的优缺点呈现出互补的特性。
- 数组支持随机访问、占用内存较少;但插入和删除元素效率低,且初始化后长度不可变。
-- 链表通过更改指针实现高效的结点插入与删除,且可以灵活调整长度;但结点访问效率低、占用内存较多。常见的链表类型包括单向链表、循环链表、双向链表。
+- 链表通过更改指针实现高效的节点插入与删除,且可以灵活调整长度;但节点访问效率低、占用内存较多。常见的链表类型包括单向链表、循环链表、双向链表。
- 动态数组,又称列表,是基于数组实现的一种数据结构。它保留了数组的优势,同时可以灵活调整长度。列表的出现极大地提高了数组的易用性,但可能导致部分内存空间浪费。
- 下表总结并对比了数组与链表的各项特性。
@@ -1722,7 +1722,7 @@
缓存局部性
-在计算机中,数据读写速度排序是“硬盘 < 内存 < CPU 缓存”。当我们访问数组元素时,计算机不仅会加载它,还会缓存其周围的其它数据,从而借助高速缓存来提升后续操作的执行速度。链表则不然,计算机只能挨个地缓存各个结点,这样的多次“搬运”降低了整体效率。
+在计算机中,数据读写速度排序是“硬盘 < 内存 < CPU 缓存”。当我们访问数组元素时,计算机不仅会加载它,还会缓存其周围的其它数据,从而借助高速缓存来提升后续操作的执行速度。链表则不然,计算机只能挨个地缓存各个节点,这样的多次“搬运”降低了整体效率。
- 下表对比了数组与链表在各种操作上的效率。
diff --git a/chapter_computational_complexity/space_complexity.assets/space_complexity_common_types.png b/chapter_computational_complexity/space_complexity.assets/space_complexity_common_types.png
index e07f6e3a9..ffc63eb3e 100644
Binary files a/chapter_computational_complexity/space_complexity.assets/space_complexity_common_types.png and b/chapter_computational_complexity/space_complexity.assets/space_complexity_common_types.png differ
diff --git a/chapter_computational_complexity/space_complexity.assets/space_complexity_exponential.png b/chapter_computational_complexity/space_complexity.assets/space_complexity_exponential.png
index 5074542cd..4756e3b5d 100644
Binary files a/chapter_computational_complexity/space_complexity.assets/space_complexity_exponential.png and b/chapter_computational_complexity/space_complexity.assets/space_complexity_exponential.png differ
diff --git a/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_linear.png b/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_linear.png
index 7f7c7e1a6..ce14ea297 100644
Binary files a/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_linear.png and b/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_linear.png differ
diff --git a/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_quadratic.png b/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_quadratic.png
index c454404cc..6ec499791 100644
Binary files a/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_quadratic.png and b/chapter_computational_complexity/space_complexity.assets/space_complexity_recursive_quadratic.png differ
diff --git a/chapter_computational_complexity/space_complexity.assets/space_types.png b/chapter_computational_complexity/space_complexity.assets/space_types.png
index 1fd77a72a..2aa3d3770 100644
Binary files a/chapter_computational_complexity/space_complexity.assets/space_types.png and b/chapter_computational_complexity/space_complexity.assets/space_types.png differ
diff --git a/chapter_computational_complexity/space_complexity/index.html b/chapter_computational_complexity/space_complexity/index.html
index da8f9e247..bedb2474c 100644
--- a/chapter_computational_complexity/space_complexity/index.html
+++ b/chapter_computational_complexity/space_complexity/index.html
@@ -1907,8 +1907,8 @@
""" 类 """
class Node:
def __init__(self, x: int):
- self.val: int = x # 结点值
- self.next: Optional[Node] = None # 指向下一结点的指针(引用)
+ self.val: int = x # 节点值
+ self.next: Optional[Node] = None # 指向下一节点的指针(引用)
""" 函数 """
def function() -> int:
@@ -1956,8 +1956,8 @@
val;
next;
constructor(val) {
- this.val = val === undefined ? 0 : val; // 结点值
- this.next = null; // 指向下一结点的引用
+ this.val = val === undefined ? 0 : val; // 节点值
+ this.next = null; // 指向下一节点的引用
}
}
@@ -1982,8 +1982,8 @@
val: number;
next: Node | null;
constructor(val?: number) {
- this.val = val === undefined ? 0 : val; // 结点值
- this.next = null; // 指向下一结点的引用
+ this.val = val === undefined ? 0 : val; // 节点值
+ this.next = null; // 指向下一节点的引用
}
}
@@ -3055,7 +3055,7 @@ O(1) < O(\log n) < O(n) < O(n^2) < O(2^n) \newline
Fig. 递归函数产生的平方阶空间复杂度
指数阶 \(O(2^n)\)¶
-指数阶常见于二叉树。高度为 \(n\) 的「满二叉树」的结点数量为 \(2^n - 1\) ,占用 \(O(2^n)\) 空间。
+指数阶常见于二叉树。高度为 \(n\) 的「满二叉树」的节点数量为 \(2^n - 1\) ,占用 \(O(2^n)\) 空间。
diff --git a/chapter_computational_complexity/time_complexity.assets/asymptotic_upper_bound.png b/chapter_computational_complexity/time_complexity.assets/asymptotic_upper_bound.png
index 9d426349f..91494fdb2 100644
Binary files a/chapter_computational_complexity/time_complexity.assets/asymptotic_upper_bound.png and b/chapter_computational_complexity/time_complexity.assets/asymptotic_upper_bound.png differ
diff --git a/chapter_computational_complexity/time_complexity.assets/time_complexity_common_types.png b/chapter_computational_complexity/time_complexity.assets/time_complexity_common_types.png
index 31ce85a25..0494758d3 100644
Binary files a/chapter_computational_complexity/time_complexity.assets/time_complexity_common_types.png and b/chapter_computational_complexity/time_complexity.assets/time_complexity_common_types.png differ
diff --git a/chapter_computational_complexity/time_complexity.assets/time_complexity_constant_linear_quadratic.png b/chapter_computational_complexity/time_complexity.assets/time_complexity_constant_linear_quadratic.png
index 2532ffa4b..ffca66e0a 100644
Binary files a/chapter_computational_complexity/time_complexity.assets/time_complexity_constant_linear_quadratic.png and b/chapter_computational_complexity/time_complexity.assets/time_complexity_constant_linear_quadratic.png differ
diff --git a/chapter_computational_complexity/time_complexity.assets/time_complexity_exponential.png b/chapter_computational_complexity/time_complexity.assets/time_complexity_exponential.png
index f4f963767..15bfdfa74 100644
Binary files a/chapter_computational_complexity/time_complexity.assets/time_complexity_exponential.png and b/chapter_computational_complexity/time_complexity.assets/time_complexity_exponential.png differ
diff --git a/chapter_computational_complexity/time_complexity.assets/time_complexity_factorial.png b/chapter_computational_complexity/time_complexity.assets/time_complexity_factorial.png
index 48834467c..92221db14 100644
Binary files a/chapter_computational_complexity/time_complexity.assets/time_complexity_factorial.png and b/chapter_computational_complexity/time_complexity.assets/time_complexity_factorial.png differ
diff --git a/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic.png b/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic.png
index c3343abdd..f93a42f2e 100644
Binary files a/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic.png and b/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic.png differ
diff --git a/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic_linear.png b/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic_linear.png
index b7552b529..e60dfaf31 100644
Binary files a/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic_linear.png and b/chapter_computational_complexity/time_complexity.assets/time_complexity_logarithmic_linear.png differ
diff --git a/chapter_computational_complexity/time_complexity.assets/time_complexity_simple_example.png b/chapter_computational_complexity/time_complexity.assets/time_complexity_simple_example.png
index 622c76f13..45989dbb0 100644
Binary files a/chapter_computational_complexity/time_complexity.assets/time_complexity_simple_example.png and b/chapter_computational_complexity/time_complexity.assets/time_complexity_simple_example.png differ
diff --git a/chapter_data_structure/classification_of_data_structure.assets/classification_logic_structure.png b/chapter_data_structure/classification_of_data_structure.assets/classification_logic_structure.png
index 192c855a5..7066b7e4f 100644
Binary files a/chapter_data_structure/classification_of_data_structure.assets/classification_logic_structure.png and b/chapter_data_structure/classification_of_data_structure.assets/classification_logic_structure.png differ
diff --git a/chapter_data_structure/classification_of_data_structure.assets/classification_phisical_structure.png b/chapter_data_structure/classification_of_data_structure.assets/classification_phisical_structure.png
index be69670c2..574cc3912 100644
Binary files a/chapter_data_structure/classification_of_data_structure.assets/classification_phisical_structure.png and b/chapter_data_structure/classification_of_data_structure.assets/classification_phisical_structure.png differ
diff --git a/chapter_data_structure/classification_of_data_structure/index.html b/chapter_data_structure/classification_of_data_structure/index.html
index 8a87ceec4..ee4742ab8 100644
--- a/chapter_data_structure/classification_of_data_structure/index.html
+++ b/chapter_data_structure/classification_of_data_structure/index.html
@@ -1742,7 +1742,7 @@
3.2. 数据结构分类¶
数据结构可以从逻辑结构和物理结构两个维度进行分类。
3.2.1. 逻辑结构:线性与非线性¶
-「逻辑结构」揭示了数据元素之间的逻辑关系。在数组和链表中,数据按照顺序依次排列,体现了数据之间的线性关系;而在树中,数据从顶部向下按层次排列,表现出祖先与后代之间的派生关系;图则由结点和边构成,反映了复杂的网络关系。
+「逻辑结构」揭示了数据元素之间的逻辑关系。在数组和链表中,数据按照顺序依次排列,体现了数据之间的线性关系;而在树中,数据从顶部向下按层次排列,表现出祖先与后代之间的派生关系;图则由节点和边构成,反映了复杂的网络关系。
逻辑结构通常分为「线性」和「非线性」两类。线性结构比较直观,指数据在逻辑关系上呈线性排列;非线性结构则相反,呈非线性排列,例如网状或树状结构。
- 线性数据结构:数组、链表、栈、队列、哈希表;
diff --git a/chapter_data_structure/data_and_memory.assets/computer_memory_location.png b/chapter_data_structure/data_and_memory.assets/computer_memory_location.png
index fb82a4597..d0d6997de 100644
Binary files a/chapter_data_structure/data_and_memory.assets/computer_memory_location.png and b/chapter_data_structure/data_and_memory.assets/computer_memory_location.png differ
diff --git a/chapter_data_structure/data_and_memory.assets/ieee_754_float.png b/chapter_data_structure/data_and_memory.assets/ieee_754_float.png
index 27b49d0a8..897c8b7e8 100644
Binary files a/chapter_data_structure/data_and_memory.assets/ieee_754_float.png and b/chapter_data_structure/data_and_memory.assets/ieee_754_float.png differ
diff --git a/chapter_graph/graph.assets/adjacency_list.png b/chapter_graph/graph.assets/adjacency_list.png
index 4cb3b7b3a..b7d7767c2 100644
Binary files a/chapter_graph/graph.assets/adjacency_list.png and b/chapter_graph/graph.assets/adjacency_list.png differ
diff --git a/chapter_graph/graph.assets/adjacency_matrix.png b/chapter_graph/graph.assets/adjacency_matrix.png
index 2c3ecdb82..880fd4c12 100644
Binary files a/chapter_graph/graph.assets/adjacency_matrix.png and b/chapter_graph/graph.assets/adjacency_matrix.png differ
diff --git a/chapter_graph/graph.assets/connected_graph.png b/chapter_graph/graph.assets/connected_graph.png
index e7e765300..5e9c10a32 100644
Binary files a/chapter_graph/graph.assets/connected_graph.png and b/chapter_graph/graph.assets/connected_graph.png differ
diff --git a/chapter_graph/graph.assets/directed_graph.png b/chapter_graph/graph.assets/directed_graph.png
index e3affc6f1..632d837e3 100644
Binary files a/chapter_graph/graph.assets/directed_graph.png and b/chapter_graph/graph.assets/directed_graph.png differ
diff --git a/chapter_graph/graph.assets/linkedlist_tree_graph.png b/chapter_graph/graph.assets/linkedlist_tree_graph.png
index 2cae356d2..6f3653d60 100644
Binary files a/chapter_graph/graph.assets/linkedlist_tree_graph.png and b/chapter_graph/graph.assets/linkedlist_tree_graph.png differ
diff --git a/chapter_graph/graph.assets/weighted_graph.png b/chapter_graph/graph.assets/weighted_graph.png
index 97a9f8fd3..0dc256619 100644
Binary files a/chapter_graph/graph.assets/weighted_graph.png and b/chapter_graph/graph.assets/weighted_graph.png differ
diff --git a/chapter_graph/graph/index.html b/chapter_graph/graph/index.html
index 64319dd80..2e24974d9 100644
--- a/chapter_graph/graph/index.html
+++ b/chapter_graph/graph/index.html
@@ -1819,7 +1819,7 @@ G & = \{ V, E \} \newline

Fig. 链表、树、图之间的关系
-那么,图与其他数据结构的关系是什么?如果我们把「顶点」看作结点,把「边」看作连接各个结点的指针,则可将「图」看作是一种从「链表」拓展而来的数据结构。相较于线性关系(链表)和分治关系(树),网络关系(图)的自由度更高,从而更为复杂。
+那么,图与其他数据结构的关系是什么?如果我们把「顶点」看作节点,把「边」看作连接各个节点的指针,则可将「图」看作是一种从「链表」拓展而来的数据结构。相较于线性关系(链表)和分治关系(树),网络关系(图)的自由度更高,从而更为复杂。
9.1.1. 图常见类型¶
根据边是否具有方向,可分为「无向图 Undirected Graph」和「有向图 Directed Graph」。
@@ -1863,7 +1863,7 @@ G & = \{ V, E \} \newline
使用邻接矩阵表示图时,我们可以直接访问矩阵元素以获取边,因此增删查操作的效率很高,时间复杂度均为 \(O(1)\) 。然而,矩阵的空间复杂度为 \(O(n^2)\) ,内存占用较多。
邻接表¶
-「邻接表 Adjacency List」使用 \(n\) 个链表来表示图,链表结点表示顶点。第 \(i\) 条链表对应顶点 \(i\) ,其中存储了该顶点的所有邻接顶点(即与该顶点相连的顶点)。
+「邻接表 Adjacency List」使用 \(n\) 个链表来表示图,链表节点表示顶点。第 \(i\) 条链表对应顶点 \(i\) ,其中存储了该顶点的所有邻接顶点(即与该顶点相连的顶点)。

Fig. 图的邻接表表示
diff --git a/chapter_graph/graph_operations.assets/adjacency_list_add_edge.png b/chapter_graph/graph_operations.assets/adjacency_list_add_edge.png
index d521d2575..8eb8925eb 100644
Binary files a/chapter_graph/graph_operations.assets/adjacency_list_add_edge.png and b/chapter_graph/graph_operations.assets/adjacency_list_add_edge.png differ
diff --git a/chapter_graph/graph_operations.assets/adjacency_list_add_vertex.png b/chapter_graph/graph_operations.assets/adjacency_list_add_vertex.png
index 1909e8441..f9af5e56f 100644
Binary files a/chapter_graph/graph_operations.assets/adjacency_list_add_vertex.png and b/chapter_graph/graph_operations.assets/adjacency_list_add_vertex.png differ
diff --git a/chapter_graph/graph_operations.assets/adjacency_list_initialization.png b/chapter_graph/graph_operations.assets/adjacency_list_initialization.png
index 7335a7c50..b91878855 100644
Binary files a/chapter_graph/graph_operations.assets/adjacency_list_initialization.png and b/chapter_graph/graph_operations.assets/adjacency_list_initialization.png differ
diff --git a/chapter_graph/graph_operations.assets/adjacency_list_remove_edge.png b/chapter_graph/graph_operations.assets/adjacency_list_remove_edge.png
index 2374cbbfc..f2bd5690b 100644
Binary files a/chapter_graph/graph_operations.assets/adjacency_list_remove_edge.png and b/chapter_graph/graph_operations.assets/adjacency_list_remove_edge.png differ
diff --git a/chapter_graph/graph_operations.assets/adjacency_list_remove_vertex.png b/chapter_graph/graph_operations.assets/adjacency_list_remove_vertex.png
index 7fb4627fc..b6b9a38fb 100644
Binary files a/chapter_graph/graph_operations.assets/adjacency_list_remove_vertex.png and b/chapter_graph/graph_operations.assets/adjacency_list_remove_vertex.png differ
diff --git a/chapter_graph/graph_operations.assets/adjacency_matrix_add_edge.png b/chapter_graph/graph_operations.assets/adjacency_matrix_add_edge.png
index a17457303..08cfbdd6f 100644
Binary files a/chapter_graph/graph_operations.assets/adjacency_matrix_add_edge.png and b/chapter_graph/graph_operations.assets/adjacency_matrix_add_edge.png differ
diff --git a/chapter_graph/graph_operations.assets/adjacency_matrix_add_vertex.png b/chapter_graph/graph_operations.assets/adjacency_matrix_add_vertex.png
index 53c908e08..323e8af13 100644
Binary files a/chapter_graph/graph_operations.assets/adjacency_matrix_add_vertex.png and b/chapter_graph/graph_operations.assets/adjacency_matrix_add_vertex.png differ
diff --git a/chapter_graph/graph_operations.assets/adjacency_matrix_initialization.png b/chapter_graph/graph_operations.assets/adjacency_matrix_initialization.png
index c34664898..6734d00af 100644
Binary files a/chapter_graph/graph_operations.assets/adjacency_matrix_initialization.png and b/chapter_graph/graph_operations.assets/adjacency_matrix_initialization.png differ
diff --git a/chapter_graph/graph_operations.assets/adjacency_matrix_remove_edge.png b/chapter_graph/graph_operations.assets/adjacency_matrix_remove_edge.png
index cc0cd5198..3da9fc105 100644
Binary files a/chapter_graph/graph_operations.assets/adjacency_matrix_remove_edge.png and b/chapter_graph/graph_operations.assets/adjacency_matrix_remove_edge.png differ
diff --git a/chapter_graph/graph_operations.assets/adjacency_matrix_remove_vertex.png b/chapter_graph/graph_operations.assets/adjacency_matrix_remove_vertex.png
index ca239cda5..ea1b101eb 100644
Binary files a/chapter_graph/graph_operations.assets/adjacency_matrix_remove_vertex.png and b/chapter_graph/graph_operations.assets/adjacency_matrix_remove_vertex.png differ
diff --git a/chapter_graph/graph_operations/index.html b/chapter_graph/graph_operations/index.html
index e15ea7ce6..6379b7b46 100644
--- a/chapter_graph/graph_operations/index.html
+++ b/chapter_graph/graph_operations/index.html
@@ -2514,7 +2514,7 @@
- 添加边:在顶点对应链表的末尾添加边即可,使用 \(O(1)\) 时间。因为是无向图,所以需要同时添加两个方向的边。
- 删除边:在顶点对应链表中查找并删除指定边,使用 \(O(m)\) 时间。在无向图中,需要同时删除两个方向的边。
-- 添加顶点:在邻接表中添加一个链表,并将新增顶点作为链表头结点,使用 \(O(1)\) 时间。
+- 添加顶点:在邻接表中添加一个链表,并将新增顶点作为链表头节点,使用 \(O(1)\) 时间。
- 删除顶点:需遍历整个邻接表,删除包含指定顶点的所有边,使用 \(O(1)\) 时间。
- 初始化:在邻接表中创建 \(n\) 个顶点和 \(2m\) 条边,使用 \(O(n + m)\) 时间。
@@ -2537,7 +2537,7 @@
-以下是基于邻接表实现图的代码示例。细心的同学可能注意到,我们在邻接表中使用 Vertex 结点类来表示顶点,这样做的原因有:
+以下是基于邻接表实现图的代码示例。细心的同学可能注意到,我们在邻接表中使用 Vertex 节点类来表示顶点,这样做的原因有:
- 如果我们选择通过顶点值来区分不同顶点,那么值重复的顶点将无法被区分。
- 如果类似邻接矩阵那样,使用顶点列表索引来区分不同顶点。那么,假设我们想要删除索引为 \(i\) 的顶点,则需要遍历整个邻接表,将其中 \(> i\) 的索引全部减 \(1\),这样操作效率较低。
@@ -2625,7 +2625,7 @@
// 邻接表,key: 顶点,value:该顶点的所有邻接顶点
unordered_map<Vertex*, vector<Vertex*>> adjList;
- /* 在 vector 中删除指定结点 */
+ /* 在 vector 中删除指定节点 */
void remove(vector<Vertex*> &vec, Vertex *vet) {
for (int i = 0; i < vec.size(); i++) {
if (vec[i] == vet) {
diff --git a/chapter_graph/graph_traversal.assets/graph_bfs.png b/chapter_graph/graph_traversal.assets/graph_bfs.png
index da53cbaad..08ef3190b 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_bfs.png and b/chapter_graph/graph_traversal.assets/graph_bfs.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_bfs_step1.png b/chapter_graph/graph_traversal.assets/graph_bfs_step1.png
index fa347f1b4..36638b826 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_bfs_step1.png and b/chapter_graph/graph_traversal.assets/graph_bfs_step1.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_bfs_step10.png b/chapter_graph/graph_traversal.assets/graph_bfs_step10.png
index ccf68bb70..97fc1b948 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_bfs_step10.png and b/chapter_graph/graph_traversal.assets/graph_bfs_step10.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_bfs_step11.png b/chapter_graph/graph_traversal.assets/graph_bfs_step11.png
index 29ad7c4cc..872e726ec 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_bfs_step11.png and b/chapter_graph/graph_traversal.assets/graph_bfs_step11.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_bfs_step2.png b/chapter_graph/graph_traversal.assets/graph_bfs_step2.png
index 027a466e9..0c69ffe56 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_bfs_step2.png and b/chapter_graph/graph_traversal.assets/graph_bfs_step2.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_bfs_step3.png b/chapter_graph/graph_traversal.assets/graph_bfs_step3.png
index 6fe0ea6e4..cfc006514 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_bfs_step3.png and b/chapter_graph/graph_traversal.assets/graph_bfs_step3.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_bfs_step4.png b/chapter_graph/graph_traversal.assets/graph_bfs_step4.png
index 3c023d9b1..cccb9aa5d 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_bfs_step4.png and b/chapter_graph/graph_traversal.assets/graph_bfs_step4.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_bfs_step5.png b/chapter_graph/graph_traversal.assets/graph_bfs_step5.png
index 28234f2af..efbb8d164 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_bfs_step5.png and b/chapter_graph/graph_traversal.assets/graph_bfs_step5.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_bfs_step6.png b/chapter_graph/graph_traversal.assets/graph_bfs_step6.png
index a909bdfc9..c709d3511 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_bfs_step6.png and b/chapter_graph/graph_traversal.assets/graph_bfs_step6.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_bfs_step7.png b/chapter_graph/graph_traversal.assets/graph_bfs_step7.png
index f80b03ddb..c9084860b 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_bfs_step7.png and b/chapter_graph/graph_traversal.assets/graph_bfs_step7.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_bfs_step8.png b/chapter_graph/graph_traversal.assets/graph_bfs_step8.png
index c7c01b813..ee6604746 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_bfs_step8.png and b/chapter_graph/graph_traversal.assets/graph_bfs_step8.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_bfs_step9.png b/chapter_graph/graph_traversal.assets/graph_bfs_step9.png
index 947559980..e7ceb7a84 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_bfs_step9.png and b/chapter_graph/graph_traversal.assets/graph_bfs_step9.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_dfs.png b/chapter_graph/graph_traversal.assets/graph_dfs.png
index 2116a55ef..a26c51f7d 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_dfs.png and b/chapter_graph/graph_traversal.assets/graph_dfs.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_dfs_step1.png b/chapter_graph/graph_traversal.assets/graph_dfs_step1.png
index d94eff937..ee706b743 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_dfs_step1.png and b/chapter_graph/graph_traversal.assets/graph_dfs_step1.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_dfs_step10.png b/chapter_graph/graph_traversal.assets/graph_dfs_step10.png
index 9d00294df..e34d1df22 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_dfs_step10.png and b/chapter_graph/graph_traversal.assets/graph_dfs_step10.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_dfs_step11.png b/chapter_graph/graph_traversal.assets/graph_dfs_step11.png
index 9533f1e74..49a3fb965 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_dfs_step11.png and b/chapter_graph/graph_traversal.assets/graph_dfs_step11.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_dfs_step2.png b/chapter_graph/graph_traversal.assets/graph_dfs_step2.png
index 991e835b3..13bae891e 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_dfs_step2.png and b/chapter_graph/graph_traversal.assets/graph_dfs_step2.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_dfs_step3.png b/chapter_graph/graph_traversal.assets/graph_dfs_step3.png
index d0b63e57e..3c4c4b1e9 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_dfs_step3.png and b/chapter_graph/graph_traversal.assets/graph_dfs_step3.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_dfs_step4.png b/chapter_graph/graph_traversal.assets/graph_dfs_step4.png
index becffab33..9e0286e0c 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_dfs_step4.png and b/chapter_graph/graph_traversal.assets/graph_dfs_step4.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_dfs_step5.png b/chapter_graph/graph_traversal.assets/graph_dfs_step5.png
index 0e5cd9534..6da4b0d82 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_dfs_step5.png and b/chapter_graph/graph_traversal.assets/graph_dfs_step5.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_dfs_step6.png b/chapter_graph/graph_traversal.assets/graph_dfs_step6.png
index d9ea117cc..2cccc7312 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_dfs_step6.png and b/chapter_graph/graph_traversal.assets/graph_dfs_step6.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_dfs_step7.png b/chapter_graph/graph_traversal.assets/graph_dfs_step7.png
index 1503a6975..2291e24f6 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_dfs_step7.png and b/chapter_graph/graph_traversal.assets/graph_dfs_step7.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_dfs_step8.png b/chapter_graph/graph_traversal.assets/graph_dfs_step8.png
index 92dee73f6..e464862f8 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_dfs_step8.png and b/chapter_graph/graph_traversal.assets/graph_dfs_step8.png differ
diff --git a/chapter_graph/graph_traversal.assets/graph_dfs_step9.png b/chapter_graph/graph_traversal.assets/graph_dfs_step9.png
index 5982b88c9..b19b5c384 100644
Binary files a/chapter_graph/graph_traversal.assets/graph_dfs_step9.png and b/chapter_graph/graph_traversal.assets/graph_dfs_step9.png differ
diff --git a/chapter_graph/graph_traversal/index.html b/chapter_graph/graph_traversal/index.html
index 356e4f336..32e634f71 100644
--- a/chapter_graph/graph_traversal/index.html
+++ b/chapter_graph/graph_traversal/index.html
@@ -1838,7 +1838,7 @@
- 在循环的每轮迭代中,弹出队首顶点并记录访问,然后将该顶点的所有邻接顶点加入到队列尾部;
- 循环步骤
2. ,直到所有顶点被访问完成后结束;
-为了防止重复遍历顶点,我们需要借助一个哈希表 visited 来记录哪些结点已被访问。
+为了防止重复遍历顶点,我们需要借助一个哈希表 visited 来记录哪些节点已被访问。
diff --git a/chapter_hashing/hash_collision.assets/hash_collision_chaining.png b/chapter_hashing/hash_collision.assets/hash_collision_chaining.png
index e0c91ec59..6653bfa12 100644
Binary files a/chapter_hashing/hash_collision.assets/hash_collision_chaining.png and b/chapter_hashing/hash_collision.assets/hash_collision_chaining.png differ
diff --git a/chapter_hashing/hash_collision.assets/hash_collision_linear_probing.png b/chapter_hashing/hash_collision.assets/hash_collision_linear_probing.png
index 96b3478a5..31263aabe 100644
Binary files a/chapter_hashing/hash_collision.assets/hash_collision_linear_probing.png and b/chapter_hashing/hash_collision.assets/hash_collision_linear_probing.png differ
diff --git a/chapter_hashing/hash_collision/index.html b/chapter_hashing/hash_collision/index.html
index 76ba7444d..0e20dcd6f 100644
--- a/chapter_hashing/hash_collision/index.html
+++ b/chapter_hashing/hash_collision/index.html
@@ -1809,13 +1809,13 @@
链式地址下,哈希表的操作方法包括:
-- 查询元素:输入 key ,经过哈希函数得到数组索引,即可访问链表头结点,然后遍历链表并对比 key 以查找目标键值对。
-- 添加元素:先通过哈希函数访问链表头结点,然后将结点(即键值对)添加到链表中。
-- 删除元素:根据哈希函数的结果访问链表头部,接着遍历链表以查找目标结点,并将其删除。
+- 查询元素:输入 key ,经过哈希函数得到数组索引,即可访问链表头节点,然后遍历链表并对比 key 以查找目标键值对。
+- 添加元素:先通过哈希函数访问链表头节点,然后将节点(即键值对)添加到链表中。
+- 删除元素:根据哈希函数的结果访问链表头部,接着遍历链表以查找目标节点,并将其删除。
尽管链式地址法解决了哈希冲突问题,但仍存在一些局限性,包括:
-- 占用空间增大,由于链表或二叉树包含结点指针,相比数组更加耗费内存空间;
+- 占用空间增大,由于链表或二叉树包含节点指针,相比数组更加耗费内存空间;
- 查询效率降低,因为需要线性遍历链表来查找对应元素;
为了提高操作效率,可以将链表转换为「AVL 树」或「红黑树」,将查询操作的时间复杂度优化至 \(O(\log n)\) 。
diff --git a/chapter_hashing/hash_map.assets/hash_collision.png b/chapter_hashing/hash_map.assets/hash_collision.png
index 91d7ff3a2..2d5d91e1d 100644
Binary files a/chapter_hashing/hash_map.assets/hash_collision.png and b/chapter_hashing/hash_map.assets/hash_collision.png differ
diff --git a/chapter_hashing/hash_map.assets/hash_function.png b/chapter_hashing/hash_map.assets/hash_function.png
index f47b21a7a..18e0f0110 100644
Binary files a/chapter_hashing/hash_map.assets/hash_function.png and b/chapter_hashing/hash_map.assets/hash_function.png differ
diff --git a/chapter_hashing/hash_map.assets/hash_map.png b/chapter_hashing/hash_map.assets/hash_map.png
index 68ba0f4f4..124dacd3a 100644
Binary files a/chapter_hashing/hash_map.assets/hash_map.png and b/chapter_hashing/hash_map.assets/hash_map.png differ
diff --git a/chapter_hashing/hash_map/index.html b/chapter_hashing/hash_map/index.html
index c9d91b9e6..8d7207085 100644
--- a/chapter_hashing/hash_map/index.html
+++ b/chapter_hashing/hash_map/index.html
@@ -1778,8 +1778,8 @@
- 无序数组:每个元素为
[学号, 姓名] ;
- 有序数组:将
1. 中的数组按照学号从小到大排序;
-- 链表:每个结点的值为
[学号, 姓名] ;
-- 二叉搜索树:每个结点的值为
[学号, 姓名] ,根据学号大小来构建树;
+- 链表:每个节点的值为
[学号, 姓名] ;
+- 二叉搜索树:每个节点的值为
[学号, 姓名] ,根据学号大小来构建树;
各项操作的时间复杂度如下表所示(详解可见二叉搜索树章节)。无论是查找元素还是增删元素,哈希表的时间复杂度都是 \(O(1)\),全面胜出!
diff --git a/chapter_heap/build_heap.assets/heapify_operations_count.png b/chapter_heap/build_heap.assets/heapify_operations_count.png
index d4095968e..079c53e1a 100644
Binary files a/chapter_heap/build_heap.assets/heapify_operations_count.png and b/chapter_heap/build_heap.assets/heapify_operations_count.png differ
diff --git a/chapter_heap/build_heap/index.html b/chapter_heap/build_heap/index.html
index 5348ad9b5..9a829244f 100644
--- a/chapter_heap/build_heap/index.html
+++ b/chapter_heap/build_heap/index.html
@@ -1786,7 +1786,7 @@
最直接的方法是借助“元素入堆操作”实现,首先创建一个空堆,然后将列表元素依次添加到堆中。
设元素数量为 \(n\) ,则最后一个元素入堆的时间复杂度为 \(O(\log n)\) 。在依次添加元素时,堆的平均长度为 \(\frac{n}{2}\) ,因此该方法的总体时间复杂度为 \(O(n \log n)\) 。
基于堆化操作实现¶
-有趣的是,存在一种更高效的建堆方法,其时间复杂度仅为 \(O(n)\) 。我们先将列表所有元素原封不动添加到堆中,然后迭代地对各个结点执行“从顶至底堆化”。当然,我们不需要对叶结点执行堆化操作,因为它们没有子结点。
+有趣的是,存在一种更高效的建堆方法,其时间复杂度仅为 \(O(n)\) 。我们先将列表所有元素原封不动添加到堆中,然后迭代地对各个节点执行“从顶至底堆化”。当然,我们不需要对叶节点执行堆化操作,因为它们没有子节点。
@@ -1794,7 +1794,7 @@
MaxHeap(List<Integer> nums) {
// 将列表元素原封不动添加进堆
maxHeap = new ArrayList<>(nums);
- // 堆化除叶结点以外的其他所有结点
+ // 堆化除叶节点以外的其他所有节点
for (int i = parent(size() - 1); i >= 0; i--) {
siftDown(i);
}
@@ -1806,7 +1806,7 @@
MaxHeap(vector<int> nums) {
// 将列表元素原封不动添加进堆
maxHeap = nums;
- // 堆化除叶结点以外的其他所有结点
+ // 堆化除叶节点以外的其他所有节点
for (int i = parent(size() - 1); i >= 0; i--) {
siftDown(i);
}
@@ -1818,7 +1818,7 @@
""" 构造方法 """
# 将列表元素原封不动添加进堆
self.max_heap = nums
- # 堆化除叶结点以外的其他所有结点
+ # 堆化除叶节点以外的其他所有节点
for i in range(self.parent(self.size() - 1), -1, -1):
self.sift_down(i)
@@ -1829,7 +1829,7 @@
// 将列表元素原封不动添加进堆
h := &maxHeap{data: nums}
for i := len(h.data) - 1; i >= 0; i-- {
- // 堆化除叶结点以外的其他所有结点
+ // 堆化除叶节点以外的其他所有节点
h.siftDown(i)
}
return h
@@ -1841,7 +1841,7 @@
constructor(nums) {
// 将列表元素原封不动添加进堆
this.#maxHeap = nums === undefined ? [] : [...nums];
- // 堆化除叶结点以外的其他所有结点
+ // 堆化除叶节点以外的其他所有节点
for (let i = this.#parent(this.size() - 1); i >= 0; i--) {
this.#siftDown(i);
}
@@ -1853,7 +1853,7 @@
constructor(nums?: number[]) {
// 将列表元素原封不动添加进堆
this.maxHeap = nums === undefined ? [] : [...nums];
- // 堆化除叶结点以外的其他所有结点
+ // 堆化除叶节点以外的其他所有节点
for (let i = this.parent(this.size() - 1); i >= 0; i--) {
this.siftDown(i);
}
@@ -1870,7 +1870,7 @@
{
// 将列表元素原封不动添加进堆
maxHeap = new List<int>(nums);
- // 堆化除叶结点以外的其他所有结点
+ // 堆化除叶节点以外的其他所有节点
var size = parent(this.size() - 1);
for (int i = size; i >= 0; i--)
{
@@ -1884,7 +1884,7 @@
init(nums: [Int]) {
// 将列表元素原封不动添加进堆
maxHeap = nums
- // 堆化除叶结点以外的其他所有结点
+ // 堆化除叶节点以外的其他所有节点
for i in stride(from: parent(i: size() - 1), through: 0, by: -1) {
siftDown(i: i)
}
@@ -1898,7 +1898,7 @@
self.max_heap = std.ArrayList(T).init(allocator);
// 将列表元素原封不动添加进堆
try self.max_heap.?.appendSlice(nums);
- // 堆化除叶结点以外的其他所有结点
+ // 堆化除叶节点以外的其他所有节点
var i: usize = parent(self.size() - 1) + 1;
while (i > 0) : (i -= 1) {
try self.siftDown(i - 1);
@@ -1911,15 +1911,15 @@
8.2.2. 复杂度分析¶
为什么第二种建堆方法的时间复杂度是 \(O(n)\) ?我们来展开推算一下。
-- 完全二叉树中,设结点总数为 \(n\) ,则叶结点数量为 \((n + 1) / 2\) ,其中 \(/\) 为向下整除。因此,在排除叶结点后,需要堆化的结点数量为 \((n - 1)/2\) ,复杂度为 \(O(n)\) ;
-- 在从顶至底堆化的过程中,每个结点最多堆化到叶结点,因此最大迭代次数为二叉树高度 \(O(\log n)\) ;
+- 完全二叉树中,设节点总数为 \(n\) ,则叶节点数量为 \((n + 1) / 2\) ,其中 \(/\) 为向下整除。因此,在排除叶节点后,需要堆化的节点数量为 \((n - 1)/2\) ,复杂度为 \(O(n)\) ;
+- 在从顶至底堆化的过程中,每个节点最多堆化到叶节点,因此最大迭代次数为二叉树高度 \(O(\log n)\) ;
-将上述两者相乘,可得到建堆过程的时间复杂度为 \(O(n \log n)\)。然而,这个估算结果并不准确,因为我们没有考虑到二叉树底层结点数量远多于顶层结点的特性。
-接下来我们来进行更为详细的计算。为了减小计算难度,我们假设树是一个“完美二叉树”,该假设不会影响计算结果的正确性。设二叉树(即堆)结点数量为 \(n\) ,树高度为 \(h\) 。上文提到,结点堆化最大迭代次数等于该结点到叶结点的距离,而该距离正是“结点高度”。
-
- Fig. 完美二叉树的各层结点数量
+将上述两者相乘,可得到建堆过程的时间复杂度为 \(O(n \log n)\)。然而,这个估算结果并不准确,因为我们没有考虑到二叉树底层节点数量远多于顶层节点的特性。
+接下来我们来进行更为详细的计算。为了减小计算难度,我们假设树是一个“完美二叉树”,该假设不会影响计算结果的正确性。设二叉树(即堆)节点数量为 \(n\) ,树高度为 \(h\) 。上文提到,节点堆化最大迭代次数等于该节点到叶节点的距离,而该距离正是“节点高度”。
+
+ Fig. 完美二叉树的各层节点数量
-因此,我们可以将各层的“结点数量 \(\times\) 结点高度”求和,从而得到所有结点的堆化迭代次数的总和。
+因此,我们可以将各层的“节点数量 \(\times\) 节点高度”求和,从而得到所有节点的堆化迭代次数的总和。
\[
T(h) = 2^0h + 2^1(h-1) + 2^2(h-2) + \cdots + 2^{(h-1)}\times1
\]
@@ -1942,7 +1942,7 @@ T(h) & = 2 \frac{1 - 2^h}{1 - 2} - h \newline
& = O(2^h)
\end{aligned}
\]
-进一步地,高度为 \(h\) 的完美二叉树的结点数量为 \(n = 2^{h+1} - 1\) ,易得复杂度为 \(O(2^h) = O(n)\) 。以上推算表明,输入列表并建堆的时间复杂度为 \(O(n)\) ,非常高效。
+进一步地,高度为 \(h\) 的完美二叉树的节点数量为 \(n = 2^{h+1} - 1\) ,易得复杂度为 \(O(2^h) = O(n)\) 。以上推算表明,输入列表并建堆的时间复杂度为 \(O(n)\) ,非常高效。
diff --git a/chapter_heap/heap.assets/heap_pop_step1.png b/chapter_heap/heap.assets/heap_pop_step1.png
index 40ade82c9..d8593777d 100644
Binary files a/chapter_heap/heap.assets/heap_pop_step1.png and b/chapter_heap/heap.assets/heap_pop_step1.png differ
diff --git a/chapter_heap/heap.assets/heap_pop_step10.png b/chapter_heap/heap.assets/heap_pop_step10.png
index 3e117b745..a71bc29c8 100644
Binary files a/chapter_heap/heap.assets/heap_pop_step10.png and b/chapter_heap/heap.assets/heap_pop_step10.png differ
diff --git a/chapter_heap/heap.assets/heap_pop_step2.png b/chapter_heap/heap.assets/heap_pop_step2.png
index c9755910c..0ae3f031a 100644
Binary files a/chapter_heap/heap.assets/heap_pop_step2.png and b/chapter_heap/heap.assets/heap_pop_step2.png differ
diff --git a/chapter_heap/heap.assets/heap_pop_step3.png b/chapter_heap/heap.assets/heap_pop_step3.png
index 68d5a7753..f62f74fc9 100644
Binary files a/chapter_heap/heap.assets/heap_pop_step3.png and b/chapter_heap/heap.assets/heap_pop_step3.png differ
diff --git a/chapter_heap/heap.assets/heap_pop_step4.png b/chapter_heap/heap.assets/heap_pop_step4.png
index 727e62fdc..459a4522f 100644
Binary files a/chapter_heap/heap.assets/heap_pop_step4.png and b/chapter_heap/heap.assets/heap_pop_step4.png differ
diff --git a/chapter_heap/heap.assets/heap_pop_step5.png b/chapter_heap/heap.assets/heap_pop_step5.png
index 866594427..ecad35674 100644
Binary files a/chapter_heap/heap.assets/heap_pop_step5.png and b/chapter_heap/heap.assets/heap_pop_step5.png differ
diff --git a/chapter_heap/heap.assets/heap_pop_step6.png b/chapter_heap/heap.assets/heap_pop_step6.png
index 99f91923d..33a00cf50 100644
Binary files a/chapter_heap/heap.assets/heap_pop_step6.png and b/chapter_heap/heap.assets/heap_pop_step6.png differ
diff --git a/chapter_heap/heap.assets/heap_pop_step7.png b/chapter_heap/heap.assets/heap_pop_step7.png
index 24f81b6fa..228e80194 100644
Binary files a/chapter_heap/heap.assets/heap_pop_step7.png and b/chapter_heap/heap.assets/heap_pop_step7.png differ
diff --git a/chapter_heap/heap.assets/heap_pop_step8.png b/chapter_heap/heap.assets/heap_pop_step8.png
index eef692392..060984342 100644
Binary files a/chapter_heap/heap.assets/heap_pop_step8.png and b/chapter_heap/heap.assets/heap_pop_step8.png differ
diff --git a/chapter_heap/heap.assets/heap_pop_step9.png b/chapter_heap/heap.assets/heap_pop_step9.png
index d11f55435..0672abe36 100644
Binary files a/chapter_heap/heap.assets/heap_pop_step9.png and b/chapter_heap/heap.assets/heap_pop_step9.png differ
diff --git a/chapter_heap/heap.assets/heap_push_step1.png b/chapter_heap/heap.assets/heap_push_step1.png
index 830093e06..cb0466413 100644
Binary files a/chapter_heap/heap.assets/heap_push_step1.png and b/chapter_heap/heap.assets/heap_push_step1.png differ
diff --git a/chapter_heap/heap.assets/heap_push_step2.png b/chapter_heap/heap.assets/heap_push_step2.png
index e692e61f3..49d6765b9 100644
Binary files a/chapter_heap/heap.assets/heap_push_step2.png and b/chapter_heap/heap.assets/heap_push_step2.png differ
diff --git a/chapter_heap/heap.assets/heap_push_step3.png b/chapter_heap/heap.assets/heap_push_step3.png
index f75050dda..addd2748f 100644
Binary files a/chapter_heap/heap.assets/heap_push_step3.png and b/chapter_heap/heap.assets/heap_push_step3.png differ
diff --git a/chapter_heap/heap.assets/heap_push_step4.png b/chapter_heap/heap.assets/heap_push_step4.png
index 7d938bce1..69eac84da 100644
Binary files a/chapter_heap/heap.assets/heap_push_step4.png and b/chapter_heap/heap.assets/heap_push_step4.png differ
diff --git a/chapter_heap/heap.assets/heap_push_step5.png b/chapter_heap/heap.assets/heap_push_step5.png
index 10c0ad0ab..1ed9dd42c 100644
Binary files a/chapter_heap/heap.assets/heap_push_step5.png and b/chapter_heap/heap.assets/heap_push_step5.png differ
diff --git a/chapter_heap/heap.assets/heap_push_step6.png b/chapter_heap/heap.assets/heap_push_step6.png
index 29222381e..1a9a7ae33 100644
Binary files a/chapter_heap/heap.assets/heap_push_step6.png and b/chapter_heap/heap.assets/heap_push_step6.png differ
diff --git a/chapter_heap/heap.assets/min_heap_and_max_heap.png b/chapter_heap/heap.assets/min_heap_and_max_heap.png
index cee747ac4..435ce7f2c 100644
Binary files a/chapter_heap/heap.assets/min_heap_and_max_heap.png and b/chapter_heap/heap.assets/min_heap_and_max_heap.png differ
diff --git a/chapter_heap/heap.assets/representation_of_heap.png b/chapter_heap/heap.assets/representation_of_heap.png
index 9427b935d..a267d24d0 100644
Binary files a/chapter_heap/heap.assets/representation_of_heap.png and b/chapter_heap/heap.assets/representation_of_heap.png differ
diff --git a/chapter_heap/heap/index.html b/chapter_heap/heap/index.html
index 639bfc057..443a032a1 100644
--- a/chapter_heap/heap/index.html
+++ b/chapter_heap/heap/index.html
@@ -1838,17 +1838,17 @@
8.1. 堆¶
「堆 Heap」是一棵限定条件下的「完全二叉树」。根据成立条件,堆主要分为两种类型:
-- 「大顶堆 Max Heap」,任意结点的值 \(\geq\) 其子结点的值;
-- 「小顶堆 Min Heap」,任意结点的值 \(\leq\) 其子结点的值;
+- 「大顶堆 Max Heap」,任意节点的值 \(\geq\) 其子节点的值;
+- 「小顶堆 Min Heap」,任意节点的值 \(\leq\) 其子节点的值;

Fig. 小顶堆与大顶堆
8.1.1. 堆术语与性质¶
-- 由于堆是完全二叉树,因此最底层结点靠左填充,其它层结点皆被填满。
-- 二叉树中的根结点对应「堆顶」,底层最靠右结点对应「堆底」。
-- 对于大顶堆 / 小顶堆,其堆顶元素(即根结点)的值最大 / 最小。
+- 由于堆是完全二叉树,因此最底层节点靠左填充,其它层节点皆被填满。
+- 二叉树中的根节点对应「堆顶」,底层最靠右节点对应「堆底」。
+- 对于大顶堆 / 小顶堆,其堆顶元素(即根节点)的值最大 / 最小。
8.1.2. 堆常用操作¶
值得说明的是,多数编程语言提供的是「优先队列 Priority Queue」,其是一种抽象数据结构,定义为具有出队优先级的队列。
@@ -2146,8 +2146,8 @@
下文实现的是「大顶堆」,若想转换为「小顶堆」,将所有大小逻辑判断取逆(例如将 \(\geq\) 替换为 \(\leq\) )即可,有兴趣的同学可自行实现。
堆的存储与表示¶
在二叉树章节我们学过,「完全二叉树」非常适合使用「数组」来表示,而堆恰好是一棵完全二叉树,因而我们采用「数组」来存储「堆」。
-二叉树指针。使用数组表示二叉树时,元素代表结点值,索引代表结点在二叉树中的位置,而结点指针通过索引映射公式来实现。
-具体地,给定索引 \(i\) ,那么其左子结点索引为 \(2i + 1\) 、右子结点索引为 \(2i + 2\) 、父结点索引为 \((i - 1) / 2\) (向下整除)。当索引越界时,代表空结点或结点不存在。
+二叉树指针。使用数组表示二叉树时,元素代表节点值,索引代表节点在二叉树中的位置,而节点指针通过索引映射公式来实现。
+具体地,给定索引 \(i\) ,那么其左子节点索引为 \(2i + 1\) 、右子节点索引为 \(2i + 2\) 、父节点索引为 \((i - 1) / 2\) (向下整除)。当索引越界时,代表空节点或节点不存在。

Fig. 堆的表示与存储
@@ -2155,34 +2155,34 @@
-
-my_heap.cpp/* 获取左子结点索引 */
+my_heap.cpp/* 获取左子节点索引 */
int left(int i) {
return 2 * i + 1;
}
-/* 获取右子结点索引 */
+/* 获取右子节点索引 */
int right(int i) {
return 2 * i + 2;
}
-/* 获取父结点索引 */
+/* 获取父节点索引 */
int parent(int i) {
return (i - 1) / 2; // 向下取整
}
@@ -2190,30 +2190,30 @@
-
-
-
-
-
-
访问堆顶元素¶
-堆顶元素是二叉树的根结点,即列表首元素。
+堆顶元素是二叉树的根节点,即列表首元素。
@@ -2393,8 +2393,8 @@
元素入堆¶
-给定元素 val ,我们先将其添加到堆底。添加后,由于 val 可能大于堆中其它元素,此时堆的成立条件可能已经被破坏,因此需要修复从插入结点到根结点这条路径上的各个结点,该操作被称为「堆化 Heapify」。
-考虑从入堆结点开始,从底至顶执行堆化。具体地,比较插入结点与其父结点的值,若插入结点更大则将它们交换;并循环以上操作,从底至顶地修复堆中的各个结点;直至越过根结点时结束,或当遇到无需交换的结点时提前结束。
+给定元素 val ,我们先将其添加到堆底。添加后,由于 val 可能大于堆中其它元素,此时堆的成立条件可能已经被破坏,因此需要修复从插入节点到根节点这条路径上的各个节点,该操作被称为「堆化 Heapify」。
+考虑从入堆节点开始,从底至顶执行堆化。具体地,比较插入节点与其父节点的值,若插入节点更大则将它们交换;并循环以上操作,从底至顶地修复堆中的各个节点;直至越过根节点时结束,或当遇到无需交换的节点时提前结束。
@@ -2417,27 +2417,27 @@
-设结点总数为 \(n\) ,则树的高度为 \(O(\log n)\) ,易得堆化操作的循环轮数最多为 \(O(\log n)\) ,因而元素入堆操作的时间复杂度为 \(O(\log n)\) 。
+设节点总数为 \(n\) ,则树的高度为 \(O(\log n)\) ,易得堆化操作的循环轮数最多为 \(O(\log n)\) ,因而元素入堆操作的时间复杂度为 \(O(\log n)\) 。
my_heap.java/* 元素入堆 */
void push(int val) {
- // 添加结点
+ // 添加节点
maxHeap.add(val);
// 从底至顶堆化
siftUp(size() - 1);
}
-/* 从结点 i 开始,从底至顶堆化 */
+/* 从节点 i 开始,从底至顶堆化 */
void siftUp(int i) {
while (true) {
- // 获取结点 i 的父结点
+ // 获取节点 i 的父节点
int p = parent(i);
- // 当“越过根结点”或“结点无需修复”时,结束堆化
+ // 当“越过根节点”或“节点无需修复”时,结束堆化
if (p < 0 || maxHeap.get(i) <= maxHeap.get(p))
break;
- // 交换两结点
+ // 交换两节点
swap(i, p);
// 循环向上堆化
i = p;
@@ -2448,21 +2448,21 @@
my_heap.cpp/* 元素入堆 */
void push(int val) {
- // 添加结点
+ // 添加节点
maxHeap.push_back(val);
// 从底至顶堆化
siftUp(size() - 1);
}
-/* 从结点 i 开始,从底至顶堆化 */
+/* 从节点 i 开始,从底至顶堆化 */
void siftUp(int i) {
while (true) {
- // 获取结点 i 的父结点
+ // 获取节点 i 的父节点
int p = parent(i);
- // 当“越过根结点”或“结点无需修复”时,结束堆化
+ // 当“越过根节点”或“节点无需修复”时,结束堆化
if (p < 0 || maxHeap[i] <= maxHeap[p])
break;
- // 交换两结点
+ // 交换两节点
swap(maxHeap[i], maxHeap[p]);
// 循环向上堆化
i = p;
@@ -2473,20 +2473,20 @@
my_heap.pydef push(self, val: int):
""" 元素入堆 """
- # 添加结点
+ # 添加节点
self.max_heap.append(val)
# 从底至顶堆化
self.sift_up(self.size() - 1)
def sift_up(self, i: int):
- """ 从结点 i 开始,从底至顶堆化 """
+ """ 从节点 i 开始,从底至顶堆化 """
while True:
- # 获取结点 i 的父结点
+ # 获取节点 i 的父节点
p = self.parent(i)
- # 当“越过根结点”或“结点无需修复”时,结束堆化
+ # 当“越过根节点”或“节点无需修复”时,结束堆化
if p < 0 or self.max_heap[i] <= self.max_heap[p]:
break
- # 交换两结点
+ # 交换两节点
self.swap(i, p)
# 循环向上堆化
i = p
@@ -2495,22 +2495,22 @@
my_heap.go/* 元素入堆 */
func (h *maxHeap) push(val any) {
- // 添加结点
+ // 添加节点
h.data = append(h.data, val)
// 从底至顶堆化
h.siftUp(len(h.data) - 1)
}
-/* 从结点 i 开始,从底至顶堆化 */
+/* 从节点 i 开始,从底至顶堆化 */
func (h *maxHeap) siftUp(i int) {
for true {
- // 获取结点 i 的父结点
+ // 获取节点 i 的父节点
p := h.parent(i)
- // 当“越过根结点”或“结点无需修复”时,结束堆化
+ // 当“越过根节点”或“节点无需修复”时,结束堆化
if p < 0 || h.data[i].(int) <= h.data[p].(int) {
break
}
- // 交换两结点
+ // 交换两节点
h.swap(i, p)
// 循环向上堆化
i = p
@@ -2521,20 +2521,20 @@
my_heap.js/* 元素入堆 */
push(val) {
- // 添加结点
+ // 添加节点
this.#maxHeap.push(val);
// 从底至顶堆化
this.#siftUp(this.size() - 1);
}
-/* 从结点 i 开始,从底至顶堆化 */
+/* 从节点 i 开始,从底至顶堆化 */
#siftUp(i) {
while (true) {
- // 获取结点 i 的父结点
+ // 获取节点 i 的父节点
const p = this.#parent(i);
- // 当“越过根结点”或“结点无需修复”时,结束堆化
+ // 当“越过根节点”或“节点无需修复”时,结束堆化
if (p < 0 || this.#maxHeap[i] <= this.#maxHeap[p]) break;
- // 交换两结点
+ // 交换两节点
this.#swap(i, p);
// 循环向上堆化
i = p;
@@ -2545,20 +2545,20 @@
my_heap.ts/* 元素入堆 */
push(val: number): void {
- // 添加结点
+ // 添加节点
this.maxHeap.push(val);
// 从底至顶堆化
this.siftUp(this.size() - 1);
}
-/* 从结点 i 开始,从底至顶堆化 */
+/* 从节点 i 开始,从底至顶堆化 */
siftUp(i: number): void {
while (true) {
- // 获取结点 i 的父结点
+ // 获取节点 i 的父节点
const p = this.parent(i);
- // 当“越过根结点”或“结点无需修复”时,结束堆化
+ // 当“越过根节点”或“节点无需修复”时,结束堆化
if (p < 0 || this.maxHeap[i] <= this.maxHeap[p]) break;
- // 交换两结点
+ // 交换两节点
this.swap(i, p);
// 循环向上堆化
i = p;
@@ -2576,23 +2576,23 @@
my_heap.cs/* 元素入堆 */
void push(int val)
{
- // 添加结点
+ // 添加节点
maxHeap.Add(val);
// 从底至顶堆化
siftUp(size() - 1);
}
-/* 从结点 i 开始,从底至顶堆化 */
+/* 从节点 i 开始,从底至顶堆化 */
void siftUp(int i)
{
while (true)
{
- // 获取结点 i 的父结点
+ // 获取节点 i 的父节点
int p = parent(i);
- // 若“越过根结点”或“结点无需修复”,则结束堆化
+ // 若“越过根节点”或“节点无需修复”,则结束堆化
if (p < 0 || maxHeap[i] <= maxHeap[p])
break;
- // 交换两结点
+ // 交换两节点
swap(i, p);
// 循环向上堆化
i = p;
@@ -2603,23 +2603,23 @@
my_heap.swift/* 元素入堆 */
func push(val: Int) {
- // 添加结点
+ // 添加节点
maxHeap.append(val)
// 从底至顶堆化
siftUp(i: size() - 1)
}
-/* 从结点 i 开始,从底至顶堆化 */
+/* 从节点 i 开始,从底至顶堆化 */
func siftUp(i: Int) {
var i = i
while true {
- // 获取结点 i 的父结点
+ // 获取节点 i 的父节点
let p = parent(i: i)
- // 当“越过根结点”或“结点无需修复”时,结束堆化
+ // 当“越过根节点”或“节点无需修复”时,结束堆化
if p < 0 || maxHeap[i] <= maxHeap[p] {
break
}
- // 交换两结点
+ // 交换两节点
swap(i: i, j: p)
// 循环向上堆化
i = p
@@ -2630,21 +2630,21 @@
my_heap.zig// 元素入堆
fn push(self: *Self, val: T) !void {
- // 添加结点
+ // 添加节点
try self.max_heap.?.append(val);
// 从底至顶堆化
try self.siftUp(self.size() - 1);
}
-// 从结点 i 开始,从底至顶堆化
+// 从节点 i 开始,从底至顶堆化
fn siftUp(self: *Self, i_: usize) !void {
var i = i_;
while (true) {
- // 获取结点 i 的父结点
+ // 获取节点 i 的父节点
var p = parent(i);
- // 当“越过根结点”或“结点无需修复”时,结束堆化
+ // 当“越过根节点”或“节点无需修复”时,结束堆化
if (p < 0 or self.max_heap.?.items[i] <= self.max_heap.?.items[p]) break;
- // 交换两结点
+ // 交换两节点
try self.swap(i, p);
// 循环向上堆化
i = p;
@@ -2655,13 +2655,13 @@
堆顶元素出堆¶
-堆顶元素是二叉树根结点,即列表首元素,如果我们直接将首元素从列表中删除,则二叉树中所有结点都会随之发生移位(索引发生变化),这样后续使用堆化修复就很麻烦了。为了尽量减少元素索引变动,采取以下操作步骤:
+堆顶元素是二叉树根节点,即列表首元素,如果我们直接将首元素从列表中删除,则二叉树中所有节点都会随之发生移位(索引发生变化),这样后续使用堆化修复就很麻烦了。为了尽量减少元素索引变动,采取以下操作步骤:
-- 交换堆顶元素与堆底元素(即交换根结点与最右叶结点);
+- 交换堆顶元素与堆底元素(即交换根节点与最右叶节点);
- 交换完成后,将堆底从列表中删除(注意,因为已经交换,实际上删除的是原来的堆顶元素);
-- 从根结点开始,从顶至底执行堆化;
+- 从根节点开始,从顶至底执行堆化;
-顾名思义,从顶至底堆化的操作方向与从底至顶堆化相反,我们比较根结点的值与其两个子结点的值,将最大的子结点与根结点执行交换,并循环以上操作,直到越过叶结点时结束,或当遇到无需交换的结点时提前结束。
+顾名思义,从顶至底堆化的操作方向与从底至顶堆化相反,我们比较根节点的值与其两个子节点的值,将最大的子节点与根节点执行交换,并循环以上操作,直到越过叶节点时结束,或当遇到无需交换的节点时提前结束。
@@ -2705,9 +2705,9 @@
// 判空处理
if (isEmpty())
throw new EmptyStackException();
- // 交换根结点与最右叶结点(即交换首元素与尾元素)
+ // 交换根节点与最右叶节点(即交换首元素与尾元素)
swap(0, size() - 1);
- // 删除结点
+ // 删除节点
int val = maxHeap.remove(size() - 1);
// 从顶至底堆化
siftDown(0);
@@ -2715,18 +2715,18 @@
return val;
}
-/* 从结点 i 开始,从顶至底堆化 */
+/* 从节点 i 开始,从顶至底堆化 */
void siftDown(int i) {
while (true) {
- // 判断结点 i, l, r 中值最大的结点,记为 ma
+ // 判断节点 i, l, r 中值最大的节点,记为 ma
int l = left(i), r = right(i), ma = i;
if (l < size() && maxHeap.get(l) > maxHeap.get(ma))
ma = l;
if (r < size() && maxHeap.get(r) > maxHeap.get(ma))
ma = r;
- // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
+ // 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if (ma == i) break;
- // 交换两结点
+ // 交换两节点
swap(i, ma);
// 循环向下堆化
i = ma;
@@ -2741,25 +2741,25 @@
if (empty()) {
throw out_of_range("堆为空");
}
- // 交换根结点与最右叶结点(即交换首元素与尾元素)
+ // 交换根节点与最右叶节点(即交换首元素与尾元素)
swap(maxHeap[0], maxHeap[size() - 1]);
- // 删除结点
+ // 删除节点
maxHeap.pop_back();
// 从顶至底堆化
siftDown(0);
}
-/* 从结点 i 开始,从顶至底堆化 */
+/* 从节点 i 开始,从顶至底堆化 */
void siftDown(int i) {
while (true) {
- // 判断结点 i, l, r 中值最大的结点,记为 ma
+ // 判断节点 i, l, r 中值最大的节点,记为 ma
int l = left(i), r = right(i), ma = i;
- // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
+ // 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if (l < size() && maxHeap[l] > maxHeap[ma])
ma = l;
if (r < size() && maxHeap[r] > maxHeap[ma])
ma = r;
- // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
+ // 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if (ma == i)
break;
swap(maxHeap[i], maxHeap[ma]);
@@ -2774,9 +2774,9 @@
""" 元素出堆 """
# 判空处理
assert not self.is_empty()
- # 交换根结点与最右叶结点(即交换首元素与尾元素)
+ # 交换根节点与最右叶节点(即交换首元素与尾元素)
self.swap(0, self.size() - 1)
- # 删除结点
+ # 删除节点
val = self.max_heap.pop()
# 从顶至底堆化
self.sift_down(0)
@@ -2784,18 +2784,18 @@
return val
def sift_down(self, i: int):
- """ 从结点 i 开始,从顶至底堆化 """
+ """ 从节点 i 开始,从顶至底堆化 """
while True:
- # 判断结点 i, l, r 中值最大的结点,记为 ma
+ # 判断节点 i, l, r 中值最大的节点,记为 ma
l, r, ma = self.left(i), self.right(i), i
if l < self.size() and self.max_heap[l] > self.max_heap[ma]:
ma = l
if r < self.size() and self.max_heap[r] > self.max_heap[ma]:
ma = r
- # 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
+ # 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if ma == i:
break
- # 交换两结点
+ # 交换两节点
self.swap(i, ma)
# 循环向下堆化
i = ma
@@ -2809,9 +2809,9 @@
fmt.Println("error")
return nil
}
- // 交换根结点与最右叶结点(即交换首元素与尾元素)
+ // 交换根节点与最右叶节点(即交换首元素与尾元素)
h.swap(0, h.size()-1)
- // 删除结点
+ // 删除节点
val := h.data[len(h.data)-1]
h.data = h.data[:len(h.data)-1]
// 从顶至底堆化
@@ -2821,10 +2821,10 @@
return val
}
-/* 从结点 i 开始,从顶至底堆化 */
+/* 从节点 i 开始,从顶至底堆化 */
func (h *maxHeap) siftDown(i int) {
for true {
- // 判断结点 i, l, r 中值最大的结点,记为 max
+ // 判断节点 i, l, r 中值最大的节点,记为 max
l, r, max := h.left(i), h.right(i), i
if l < h.size() && h.data[l].(int) > h.data[max].(int) {
max = l
@@ -2832,11 +2832,11 @@
if r < h.size() && h.data[r].(int) > h.data[max].(int) {
max = r
}
- // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
+ // 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if max == i {
break
}
- // 交换两结点
+ // 交换两节点
h.swap(i, max)
// 循环向下堆化
i = max
@@ -2849,9 +2849,9 @@
pop() {
// 判空处理
if (this.isEmpty()) throw new Error("堆为空");
- // 交换根结点与最右叶结点(即交换首元素与尾元素)
+ // 交换根节点与最右叶节点(即交换首元素与尾元素)
this.#swap(0, this.size() - 1);
- // 删除结点
+ // 删除节点
const val = this.#maxHeap.pop();
// 从顶至底堆化
this.#siftDown(0);
@@ -2859,18 +2859,18 @@
return val;
}
-/* 从结点 i 开始,从顶至底堆化 */
+/* 从节点 i 开始,从顶至底堆化 */
#siftDown(i) {
while (true) {
- // 判断结点 i, l, r 中值最大的结点,记为 ma
+ // 判断节点 i, l, r 中值最大的节点,记为 ma
const l = this.#left(i),
r = this.#right(i);
let ma = i;
if (l < this.size() && this.#maxHeap[l] > this.#maxHeap[ma]) ma = l;
if (r < this.size() && this.#maxHeap[r] > this.#maxHeap[ma]) ma = r;
- // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
+ // 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if (ma == i) break;
- // 交换两结点
+ // 交换两节点
this.#swap(i, ma);
// 循环向下堆化
i = ma;
@@ -2883,9 +2883,9 @@
pop(): number {
// 判空处理
if (this.isEmpty()) throw new RangeError('Heap is empty.');
- // 交换根结点与最右叶结点(即交换首元素与尾元素)
+ // 交换根节点与最右叶节点(即交换首元素与尾元素)
this.swap(0, this.size() - 1);
- // 删除结点
+ // 删除节点
const val = this.maxHeap.pop();
// 从顶至底堆化
this.siftDown(0);
@@ -2893,18 +2893,18 @@
return val;
}
-/* 从结点 i 开始,从顶至底堆化 */
+/* 从节点 i 开始,从顶至底堆化 */
siftDown(i: number): void {
while (true) {
- // 判断结点 i, l, r 中值最大的结点,记为 ma
+ // 判断节点 i, l, r 中值最大的节点,记为 ma
const l = this.left(i),
r = this.right(i);
let ma = i;
if (l < this.size() && this.maxHeap[l] > this.maxHeap[ma]) ma = l;
if (r < this.size() && this.maxHeap[r] > this.maxHeap[ma]) ma = r;
- // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
+ // 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if (ma == i) break;
- // 交换两结点
+ // 交换两节点
this.swap(i, ma);
// 循环向下堆化
i = ma;
@@ -2925,9 +2925,9 @@
// 判空处理
if (isEmpty())
throw new IndexOutOfRangeException();
- // 交换根结点与最右叶结点(即交换首元素与尾元素)
+ // 交换根节点与最右叶节点(即交换首元素与尾元素)
swap(0, size() - 1);
- // 删除结点
+ // 删除节点
int val = maxHeap.Last();
maxHeap.RemoveAt(size() - 1);
// 从顶至底堆化
@@ -2936,20 +2936,20 @@
return val;
}
-/* 从结点 i 开始,从顶至底堆化 */
+/* 从节点 i 开始,从顶至底堆化 */
void siftDown(int i)
{
while (true)
{
- // 判断结点 i, l, r 中值最大的结点,记为 ma
+ // 判断节点 i, l, r 中值最大的节点,记为 ma
int l = left(i), r = right(i), ma = i;
if (l < size() && maxHeap[l] > maxHeap[ma])
ma = l;
if (r < size() && maxHeap[r] > maxHeap[ma])
ma = r;
- // 若“结点 i 最大”或“越过叶结点”,则结束堆化
+ // 若“节点 i 最大”或“越过叶节点”,则结束堆化
if (ma == i) break;
- // 交换两结点
+ // 交换两节点
swap(i, ma);
// 循环向下堆化
i = ma;
@@ -2964,9 +2964,9 @@
if isEmpty() {
fatalError("堆为空")
}
- // 交换根结点与最右叶结点(即交换首元素与尾元素)
+ // 交换根节点与最右叶节点(即交换首元素与尾元素)
swap(i: 0, j: size() - 1)
- // 删除结点
+ // 删除节点
let val = maxHeap.remove(at: size() - 1)
// 从顶至底堆化
siftDown(i: 0)
@@ -2974,11 +2974,11 @@
return val
}
-/* 从结点 i 开始,从顶至底堆化 */
+/* 从节点 i 开始,从顶至底堆化 */
func siftDown(i: Int) {
var i = i
while true {
- // 判断结点 i, l, r 中值最大的结点,记为 ma
+ // 判断节点 i, l, r 中值最大的节点,记为 ma
let l = left(i: i)
let r = right(i: i)
var ma = i
@@ -2988,11 +2988,11 @@
if r < size(), maxHeap[r] > maxHeap[ma] {
ma = r
}
- // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
+ // 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if ma == i {
break
}
- // 交换两结点
+ // 交换两节点
swap(i: i, j: ma)
// 循环向下堆化
i = ma
@@ -3005,9 +3005,9 @@
fn pop(self: *Self) !T {
// 判断处理
if (self.isEmpty()) unreachable;
- // 交换根结点与最右叶结点(即交换首元素与尾元素)
+ // 交换根节点与最右叶节点(即交换首元素与尾元素)
try self.swap(0, self.size() - 1);
- // 删除结点
+ // 删除节点
var val = self.max_heap.?.pop();
// 从顶至底堆化
try self.siftDown(0);
@@ -3015,19 +3015,19 @@
return val;
}
-// 从结点 i 开始,从顶至底堆化
+// 从节点 i 开始,从顶至底堆化
fn siftDown(self: *Self, i_: usize) !void {
var i = i_;
while (true) {
- // 判断结点 i, l, r 中值最大的结点,记为 ma
+ // 判断节点 i, l, r 中值最大的节点,记为 ma
var l = left(i);
var r = right(i);
var ma = i;
if (l < self.size() and self.max_heap.?.items[l] > self.max_heap.?.items[ma]) ma = l;
if (r < self.size() and self.max_heap.?.items[r] > self.max_heap.?.items[ma]) ma = r;
- // 若结点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
+ // 若节点 i 最大或索引 l, r 越界,则无需继续堆化,跳出
if (ma == i) break;
- // 交换两结点
+ // 交换两节点
try self.swap(i, ma);
// 循环向下堆化
i = ma;
diff --git a/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_1.png b/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_1.png
index b94a8aa6c..9eda07d77 100644
Binary files a/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_1.png and b/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_1.png differ
diff --git a/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_2.png b/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_2.png
index 39dbedfc6..e08403872 100644
Binary files a/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_2.png and b/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_2.png differ
diff --git a/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_3.png b/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_3.png
index 1463b84d1..2c0459f89 100644
Binary files a/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_3.png and b/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_3.png differ
diff --git a/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_4.png b/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_4.png
index f01d1c7cb..45f9eb2b1 100644
Binary files a/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_4.png and b/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_4.png differ
diff --git a/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_5.png b/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_5.png
index d73a2f050..95cd445c2 100644
Binary files a/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_5.png and b/chapter_introduction/algorithms_are_everywhere.assets/look_up_dictionary_step_5.png differ
diff --git a/chapter_introduction/what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png b/chapter_introduction/what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png
index bc0534293..320a55f73 100644
Binary files a/chapter_introduction/what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png and b/chapter_introduction/what_is_dsa.assets/relationship_between_data_structure_and_algorithm.png differ
diff --git a/chapter_preface/about_the_book.assets/hello_algo_mindmap.png b/chapter_preface/about_the_book.assets/hello_algo_mindmap.png
index c0f3dc066..b20b57f43 100644
Binary files a/chapter_preface/about_the_book.assets/hello_algo_mindmap.png and b/chapter_preface/about_the_book.assets/hello_algo_mindmap.png differ
diff --git a/chapter_preface/suggestions.assets/code_md_to_repo.png b/chapter_preface/suggestions.assets/code_md_to_repo.png
index 892f89023..7f1deca69 100644
Binary files a/chapter_preface/suggestions.assets/code_md_to_repo.png and b/chapter_preface/suggestions.assets/code_md_to_repo.png differ
diff --git a/chapter_preface/suggestions.assets/download_code.png b/chapter_preface/suggestions.assets/download_code.png
index 89d62ef99..66e20158d 100644
Binary files a/chapter_preface/suggestions.assets/download_code.png and b/chapter_preface/suggestions.assets/download_code.png differ
diff --git a/chapter_preface/suggestions.assets/learning_route.png b/chapter_preface/suggestions.assets/learning_route.png
index 806413392..ccca4eeb4 100644
Binary files a/chapter_preface/suggestions.assets/learning_route.png and b/chapter_preface/suggestions.assets/learning_route.png differ
diff --git a/chapter_searching/binary_search.assets/binary_search_step1.png b/chapter_searching/binary_search.assets/binary_search_step1.png
index 158ee8118..51ae59056 100644
Binary files a/chapter_searching/binary_search.assets/binary_search_step1.png and b/chapter_searching/binary_search.assets/binary_search_step1.png differ
diff --git a/chapter_searching/binary_search.assets/binary_search_step2.png b/chapter_searching/binary_search.assets/binary_search_step2.png
index 20fe3d489..00a60ea0c 100644
Binary files a/chapter_searching/binary_search.assets/binary_search_step2.png and b/chapter_searching/binary_search.assets/binary_search_step2.png differ
diff --git a/chapter_searching/binary_search.assets/binary_search_step3.png b/chapter_searching/binary_search.assets/binary_search_step3.png
index 34939df34..ad3b851fe 100644
Binary files a/chapter_searching/binary_search.assets/binary_search_step3.png and b/chapter_searching/binary_search.assets/binary_search_step3.png differ
diff --git a/chapter_searching/binary_search.assets/binary_search_step4.png b/chapter_searching/binary_search.assets/binary_search_step4.png
index c1aad5319..41578dc04 100644
Binary files a/chapter_searching/binary_search.assets/binary_search_step4.png and b/chapter_searching/binary_search.assets/binary_search_step4.png differ
diff --git a/chapter_searching/binary_search.assets/binary_search_step5.png b/chapter_searching/binary_search.assets/binary_search_step5.png
index 54f4ab23b..68f5d786e 100644
Binary files a/chapter_searching/binary_search.assets/binary_search_step5.png and b/chapter_searching/binary_search.assets/binary_search_step5.png differ
diff --git a/chapter_searching/binary_search.assets/binary_search_step6.png b/chapter_searching/binary_search.assets/binary_search_step6.png
index 0da399b2b..6208bf5d3 100644
Binary files a/chapter_searching/binary_search.assets/binary_search_step6.png and b/chapter_searching/binary_search.assets/binary_search_step6.png differ
diff --git a/chapter_searching/binary_search.assets/binary_search_step7.png b/chapter_searching/binary_search.assets/binary_search_step7.png
index 4e76757b7..f292942a5 100644
Binary files a/chapter_searching/binary_search.assets/binary_search_step7.png and b/chapter_searching/binary_search.assets/binary_search_step7.png differ
diff --git a/chapter_searching/hashing_search.assets/hash_search_index.png b/chapter_searching/hashing_search.assets/hash_search_index.png
index ab1b52152..777250b7b 100644
Binary files a/chapter_searching/hashing_search.assets/hash_search_index.png and b/chapter_searching/hashing_search.assets/hash_search_index.png differ
diff --git a/chapter_searching/hashing_search.assets/hash_search_listnode.png b/chapter_searching/hashing_search.assets/hash_search_listnode.png
index e7574799f..7e310072b 100644
Binary files a/chapter_searching/hashing_search.assets/hash_search_listnode.png and b/chapter_searching/hashing_search.assets/hash_search_listnode.png differ
diff --git a/chapter_searching/hashing_search/index.html b/chapter_searching/hashing_search/index.html
index d7c90a953..21a35f5b2 100644
--- a/chapter_searching/hashing_search/index.html
+++ b/chapter_searching/hashing_search/index.html
@@ -1860,16 +1860,16 @@
-再比如,如果我们想要给定一个目标结点值 target ,获取对应的链表结点对象,那么也可以使用哈希查找实现。
-
- Fig. 哈希查找链表结点
+再比如,如果我们想要给定一个目标节点值 target ,获取对应的链表节点对象,那么也可以使用哈希查找实现。
+
+ Fig. 哈希查找链表节点
hashing_search.java/* 哈希查找(链表) */
ListNode hashingSearchLinkedList(Map<Integer, ListNode> map, int target) {
- // 哈希表的 key: 目标结点值,value: 结点对象
+ // 哈希表的 key: 目标节点值,value: 节点对象
// 若哈希表中无此 key ,返回 null
return map.getOrDefault(target, null);
}
@@ -1878,7 +1878,7 @@
hashing_search.cpp/* 哈希查找(链表) */
ListNode* hashingSearchLinkedList(unordered_map<int, ListNode*> map, int target) {
- // 哈希表的 key: 目标结点值,value: 结点对象
+ // 哈希表的 key: 目标节点值,value: 节点对象
// 若哈希表中无此 key ,返回 nullptr
if (map.find(target) == map.end())
return nullptr;
@@ -1889,7 +1889,7 @@
hashing_search.pydef hashing_search_linkedlist(mapp: dict[int, ListNode], target: int) -> ListNode | None:
""" 哈希查找(链表) """
- # 哈希表的 key: 目标元素,value: 结点对象
+ # 哈希表的 key: 目标元素,value: 节点对象
# 若哈希表中无此 key ,返回 None
return mapp.get(target, None)
@@ -1897,7 +1897,7 @@
hashing_search.go/* 哈希查找(链表) */
func hashingSearchLinkedList(m map[int]*ListNode, target int) *ListNode {
- // 哈希表的 key: 目标结点值,value: 结点对象
+ // 哈希表的 key: 目标节点值,value: 节点对象
// 若哈希表中无此 key ,返回 nil
if node, ok := m[target]; ok {
return node
@@ -1910,7 +1910,7 @@
hashing_search.js/* 哈希查找(链表) */
function hashingSearchLinkedList(map, target) {
- // 哈希表的 key: 目标结点值,value: 结点对象
+ // 哈希表的 key: 目标节点值,value: 节点对象
// 若哈希表中无此 key ,返回 null
return map.has(target) ? map.get(target) : null;
}
@@ -1919,7 +1919,7 @@
hashing_search.ts/* 哈希查找(链表) */
function hashingSearchLinkedList(map: Map<number, ListNode>, target: number): ListNode | null {
- // 哈希表的 key: 目标结点值,value: 结点对象
+ // 哈希表的 key: 目标节点值,value: 节点对象
// 若哈希表中无此 key ,返回 null
return map.has(target) ? (map.get(target) as ListNode) : null;
}
@@ -1934,7 +1934,7 @@
ListNode? hashingSearchLinkedList(Dictionary<int, ListNode> map, int target)
{
- // 哈希表的 key: 目标结点值,value: 结点对象
+ // 哈希表的 key: 目标节点值,value: 节点对象
// 若哈希表中无此 key ,返回 null
return map.GetValueOrDefault(target);
}
@@ -1943,7 +1943,7 @@
hashing_search.swift/* 哈希查找(链表) */
func hashingSearchLinkedList(map: [Int: ListNode], target: Int) -> ListNode? {
- // 哈希表的 key: 目标结点值,value: 结点对象
+ // 哈希表的 key: 目标节点值,value: 节点对象
// 若哈希表中无此 key ,返回 null
return map[target]
}
@@ -1952,7 +1952,7 @@
hashing_search.zig// 哈希查找(链表)
fn hashingSearchLinkedList(comptime T: type, map: std.AutoHashMap(T, *inc.ListNode(T)), target: T) ?*inc.ListNode(T) {
- // 哈希表的 key: 目标结点值,value: 结点对象
+ // 哈希表的 key: 目标节点值,value: 节点对象
// 若哈希表中无此 key ,返回 null
if (map.getKey(target) == null) return null;
return map.get(target);
diff --git a/chapter_searching/linear_search.assets/linear_search.png b/chapter_searching/linear_search.assets/linear_search.png
index 60389c81c..ca56d5ef0 100644
Binary files a/chapter_searching/linear_search.assets/linear_search.png and b/chapter_searching/linear_search.assets/linear_search.png differ
diff --git a/chapter_searching/linear_search/index.html b/chapter_searching/linear_search/index.html
index 453545969..164ce0a2b 100644
--- a/chapter_searching/linear_search/index.html
+++ b/chapter_searching/linear_search/index.html
@@ -1897,7 +1897,7 @@
-再比如,我们想要在给定一个目标结点值 target ,返回此结点对象,也可以在链表中进行线性查找。
+再比如,我们想要在给定一个目标节点值 target ,返回此节点对象,也可以在链表中进行线性查找。
@@ -1905,12 +1905,12 @@
ListNode linearSearchLinkedList(ListNode head, int target) {
// 遍历链表
while (head != null) {
- // 找到目标结点,返回之
+ // 找到目标节点,返回之
if (head.val == target)
return head;
head = head.next;
}
- // 未找到目标结点,返回 null
+ // 未找到目标节点,返回 null
return null;
}
@@ -1920,12 +1920,12 @@
ListNode* linearSearchLinkedList(ListNode* head, int target) {
// 遍历链表
while (head != nullptr) {
- // 找到目标结点,返回之
+ // 找到目标节点,返回之
if (head->val == target)
return head;
head = head->next;
}
- // 未找到目标结点,返回 nullptr
+ // 未找到目标节点,返回 nullptr
return nullptr;
}
@@ -1935,10 +1935,10 @@
""" 线性查找(链表) """
# 遍历链表
while head:
- if head.val == target: # 找到目标结点,返回之
+ if head.val == target: # 找到目标节点,返回之
return head
head = head.next
- return None # 未找到目标结点,返回 None
+ return None # 未找到目标节点,返回 None
@@ -1946,7 +1946,7 @@
func linearSearchLinkedList(node *ListNode, target int) *ListNode {
// 遍历链表
for node != nil {
- // 找到目标结点,返回之
+ // 找到目标节点,返回之
if node.Val == target {
return node
}
@@ -1962,13 +1962,13 @@
function linearSearchLinkedList(head, target) {
// 遍历链表
while(head) {
- // 找到目标结点,返回之
+ // 找到目标节点,返回之
if(head.val === target) {
return head;
}
head = head.next;
}
- // 未找到目标结点,返回 null
+ // 未找到目标节点,返回 null
return null;
}
@@ -1978,13 +1978,13 @@
function linearSearchLinkedList(head: ListNode | null, target: number): ListNode | null {
// 遍历链表
while (head) {
- // 找到目标结点,返回之
+ // 找到目标节点,返回之
if (head.val === target) {
return head;
}
head = head.next;
}
- // 未找到目标结点,返回 null
+ // 未找到目标节点,返回 null
return null;
}
@@ -2000,12 +2000,12 @@
// 遍历链表
while (head != null)
{
- // 找到目标结点,返回之
+ // 找到目标节点,返回之
if (head.val == target)
return head;
head = head.next;
}
- // 未找到目标结点,返回 null
+ // 未找到目标节点,返回 null
return null;
}
@@ -2016,13 +2016,13 @@
var head = head
// 遍历链表
while head != nil {
- // 找到目标结点,返回之
+ // 找到目标节点,返回之
if head?.val == target {
return head
}
head = head?.next
}
- // 未找到目标结点,返回 null
+ // 未找到目标节点,返回 null
return nil
}
@@ -2033,7 +2033,7 @@
var head = node;
// 遍历链表
while (head != null) {
- // 找到目标结点,返回之
+ // 找到目标节点,返回之
if (head.?.val == target) return head;
head = head.?.next;
}
diff --git a/chapter_sorting/bubble_sort.assets/bubble_operation_step1.png b/chapter_sorting/bubble_sort.assets/bubble_operation_step1.png
index 60b635ff4..40a6cff7f 100644
Binary files a/chapter_sorting/bubble_sort.assets/bubble_operation_step1.png and b/chapter_sorting/bubble_sort.assets/bubble_operation_step1.png differ
diff --git a/chapter_sorting/bubble_sort.assets/bubble_operation_step2.png b/chapter_sorting/bubble_sort.assets/bubble_operation_step2.png
index a06241fae..ad6f69f18 100644
Binary files a/chapter_sorting/bubble_sort.assets/bubble_operation_step2.png and b/chapter_sorting/bubble_sort.assets/bubble_operation_step2.png differ
diff --git a/chapter_sorting/bubble_sort.assets/bubble_operation_step3.png b/chapter_sorting/bubble_sort.assets/bubble_operation_step3.png
index a15f1fdcd..d8b521d18 100644
Binary files a/chapter_sorting/bubble_sort.assets/bubble_operation_step3.png and b/chapter_sorting/bubble_sort.assets/bubble_operation_step3.png differ
diff --git a/chapter_sorting/bubble_sort.assets/bubble_operation_step4.png b/chapter_sorting/bubble_sort.assets/bubble_operation_step4.png
index 53b333e54..31865cbe7 100644
Binary files a/chapter_sorting/bubble_sort.assets/bubble_operation_step4.png and b/chapter_sorting/bubble_sort.assets/bubble_operation_step4.png differ
diff --git a/chapter_sorting/bubble_sort.assets/bubble_operation_step5.png b/chapter_sorting/bubble_sort.assets/bubble_operation_step5.png
index 635498e9f..6a07b46e4 100644
Binary files a/chapter_sorting/bubble_sort.assets/bubble_operation_step5.png and b/chapter_sorting/bubble_sort.assets/bubble_operation_step5.png differ
diff --git a/chapter_sorting/bubble_sort.assets/bubble_operation_step6.png b/chapter_sorting/bubble_sort.assets/bubble_operation_step6.png
index 4fced66ee..7fa2eaf70 100644
Binary files a/chapter_sorting/bubble_sort.assets/bubble_operation_step6.png and b/chapter_sorting/bubble_sort.assets/bubble_operation_step6.png differ
diff --git a/chapter_sorting/bubble_sort.assets/bubble_operation_step7.png b/chapter_sorting/bubble_sort.assets/bubble_operation_step7.png
index db9d8817b..552e9f959 100644
Binary files a/chapter_sorting/bubble_sort.assets/bubble_operation_step7.png and b/chapter_sorting/bubble_sort.assets/bubble_operation_step7.png differ
diff --git a/chapter_sorting/bubble_sort.assets/bubble_sort_overview.png b/chapter_sorting/bubble_sort.assets/bubble_sort_overview.png
index 85554c9ed..746ec6e81 100644
Binary files a/chapter_sorting/bubble_sort.assets/bubble_sort_overview.png and b/chapter_sorting/bubble_sort.assets/bubble_sort_overview.png differ
diff --git a/chapter_sorting/bucket_sort.assets/bucket_sort_overview.png b/chapter_sorting/bucket_sort.assets/bucket_sort_overview.png
index b4e11b022..4fc4768a5 100644
Binary files a/chapter_sorting/bucket_sort.assets/bucket_sort_overview.png and b/chapter_sorting/bucket_sort.assets/bucket_sort_overview.png differ
diff --git a/chapter_sorting/bucket_sort.assets/scatter_in_buckets_distribution.png b/chapter_sorting/bucket_sort.assets/scatter_in_buckets_distribution.png
index f79c3733d..075471129 100644
Binary files a/chapter_sorting/bucket_sort.assets/scatter_in_buckets_distribution.png and b/chapter_sorting/bucket_sort.assets/scatter_in_buckets_distribution.png differ
diff --git a/chapter_sorting/bucket_sort.assets/scatter_in_buckets_recursively.png b/chapter_sorting/bucket_sort.assets/scatter_in_buckets_recursively.png
index e7d34f64a..c08598de8 100644
Binary files a/chapter_sorting/bucket_sort.assets/scatter_in_buckets_recursively.png and b/chapter_sorting/bucket_sort.assets/scatter_in_buckets_recursively.png differ
diff --git a/chapter_sorting/bucket_sort/index.html b/chapter_sorting/bucket_sort/index.html
index 8fd2a22a0..eb9e01679 100644
--- a/chapter_sorting/bucket_sort/index.html
+++ b/chapter_sorting/bucket_sort/index.html
@@ -1883,11 +1883,65 @@
-bucket_sort.js[class]{}-[func]{bucketSort}
+bucket_sort.js/* 桶排序 */
+function bucketSort(nums) {
+ // 初始化 k = n/2 个桶,预期向每个桶分配 2 个元素
+ const k = nums.length / 2;
+ const buckets = [];
+ for (let i = 0; i < k; i++) {
+ buckets.push([]);
+ }
+ // 1. 将数组元素分配到各个桶中
+ for (const num of nums) {
+ // 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]
+ const i = Math.floor(num * k);
+ // 将 num 添加进桶 i
+ buckets[i].push(num);
+ }
+ // 2. 对各个桶执行排序
+ for (const bucket of buckets) {
+ // 使用内置排序函数,也可以替换成其它排序算法
+ bucket.sort((a, b) => a - b);
+ }
+ // 3. 遍历桶合并结果
+ let i = 0;
+ for (const bucket of buckets) {
+ for (const num of bucket) {
+ nums[i++] = num;
+ }
+ }
+}
-bucket_sort.ts[class]{}-[func]{bucketSort}
+bucket_sort.ts/* 桶排序 */
+function bucketSort(nums: number[]): void {
+ // 初始化 k = n/2 个桶,预期向每个桶分配 2 个元素
+ const k = nums.length / 2;
+ const buckets: number[][] = [];
+ for (let i = 0; i < k; i++) {
+ buckets.push([]);
+ }
+ // 1. 将数组元素分配到各个桶中
+ for (const num of nums) {
+ // 输入数据范围 [0, 1),使用 num * k 映射到索引范围 [0, k-1]
+ const i = Math.floor(num * k);
+ // 将 num 添加进桶 i
+ buckets[i].push(num);
+ }
+ // 2. 对各个桶执行排序
+ for (const bucket of buckets) {
+ // 使用内置排序函数,也可以替换成其它排序算法
+ bucket.sort((a, b) => a - b);
+ }
+ // 3. 遍历桶合并结果
+ let i = 0;
+ for (const bucket of buckets) {
+ for (const num of bucket) {
+ nums[i++] = num;
+ }
+ }
+}
@@ -1944,7 +1998,7 @@
桶排序是否稳定取决于排序桶内元素的算法是否稳定。
11.6.3. 如何实现平均分配¶
桶排序的时间复杂度理论上可以达到 \(O(n)\) ,难点是需要将元素均匀分配到各个桶中,因为现实中的数据往往都不是均匀分布的。举个例子,假设我们想要把淘宝的所有商品根据价格范围平均分配到 10 个桶中,然而商品价格不是均匀分布的,100 元以下非常多、1000 元以上非常少;如果我们将价格区间平均划为 10 份,那么各个桶内的商品数量差距会非常大。
-为了实现平均分配,我们可以先大致设置一个分界线,将数据粗略分到 3 个桶,分配完后,再把商品较多的桶继续划分为 3 个桶,直至所有桶内元素数量大致平均为止。此方法本质上是生成一个递归树,让叶结点的值尽量平均。当然,不一定非要划分为 3 个桶,可以根据数据特点灵活选取。
+为了实现平均分配,我们可以先大致设置一个分界线,将数据粗略分到 3 个桶,分配完后,再把商品较多的桶继续划分为 3 个桶,直至所有桶内元素数量大致平均为止。此方法本质上是生成一个递归树,让叶节点的值尽量平均。当然,不一定非要划分为 3 个桶,可以根据数据特点灵活选取。

Fig. 递归划分桶
diff --git a/chapter_sorting/counting_sort.assets/counting_sort_overview.png b/chapter_sorting/counting_sort.assets/counting_sort_overview.png
index eb5708b20..9c8937444 100644
Binary files a/chapter_sorting/counting_sort.assets/counting_sort_overview.png and b/chapter_sorting/counting_sort.assets/counting_sort_overview.png differ
diff --git a/chapter_sorting/counting_sort.assets/counting_sort_step1.png b/chapter_sorting/counting_sort.assets/counting_sort_step1.png
index 02bc0d535..29070a509 100644
Binary files a/chapter_sorting/counting_sort.assets/counting_sort_step1.png and b/chapter_sorting/counting_sort.assets/counting_sort_step1.png differ
diff --git a/chapter_sorting/counting_sort.assets/counting_sort_step2.png b/chapter_sorting/counting_sort.assets/counting_sort_step2.png
index 498200829..24baf6f00 100644
Binary files a/chapter_sorting/counting_sort.assets/counting_sort_step2.png and b/chapter_sorting/counting_sort.assets/counting_sort_step2.png differ
diff --git a/chapter_sorting/counting_sort.assets/counting_sort_step3.png b/chapter_sorting/counting_sort.assets/counting_sort_step3.png
index 40886ecf3..bee79d9f2 100644
Binary files a/chapter_sorting/counting_sort.assets/counting_sort_step3.png and b/chapter_sorting/counting_sort.assets/counting_sort_step3.png differ
diff --git a/chapter_sorting/counting_sort.assets/counting_sort_step4.png b/chapter_sorting/counting_sort.assets/counting_sort_step4.png
index 96ee248ff..9b5625eee 100644
Binary files a/chapter_sorting/counting_sort.assets/counting_sort_step4.png and b/chapter_sorting/counting_sort.assets/counting_sort_step4.png differ
diff --git a/chapter_sorting/counting_sort.assets/counting_sort_step5.png b/chapter_sorting/counting_sort.assets/counting_sort_step5.png
index 5dd52aa18..2f3d8434a 100644
Binary files a/chapter_sorting/counting_sort.assets/counting_sort_step5.png and b/chapter_sorting/counting_sort.assets/counting_sort_step5.png differ
diff --git a/chapter_sorting/counting_sort.assets/counting_sort_step6.png b/chapter_sorting/counting_sort.assets/counting_sort_step6.png
index b6128f1b4..009ecdf04 100644
Binary files a/chapter_sorting/counting_sort.assets/counting_sort_step6.png and b/chapter_sorting/counting_sort.assets/counting_sort_step6.png differ
diff --git a/chapter_sorting/counting_sort.assets/counting_sort_step7.png b/chapter_sorting/counting_sort.assets/counting_sort_step7.png
index 32508c234..8819621bb 100644
Binary files a/chapter_sorting/counting_sort.assets/counting_sort_step7.png and b/chapter_sorting/counting_sort.assets/counting_sort_step7.png differ
diff --git a/chapter_sorting/counting_sort.assets/counting_sort_step8.png b/chapter_sorting/counting_sort.assets/counting_sort_step8.png
index 003865f6a..5118ab4a8 100644
Binary files a/chapter_sorting/counting_sort.assets/counting_sort_step8.png and b/chapter_sorting/counting_sort.assets/counting_sort_step8.png differ
diff --git a/chapter_sorting/counting_sort/index.html b/chapter_sorting/counting_sort/index.html
index 13f088a4f..75036c835 100644
--- a/chapter_sorting/counting_sort/index.html
+++ b/chapter_sorting/counting_sort/index.html
@@ -1880,11 +1880,53 @@
-counting_sort.js[class]{}-[func]{countingSortNaive}
+counting_sort.js/* 计数排序 */
+// 简单实现,无法用于排序对象
+function countingSortNaive(nums) {
+ // 1. 统计数组最大元素 m
+ let m = 0;
+ for (const num of nums) {
+ m = Math.max(m, num);
+ }
+ // 2. 统计各数字的出现次数
+ // counter[num] 代表 num 的出现次数
+ const counter = new Array(m + 1).fill(0);
+ for (const num of nums) {
+ counter[num]++;
+ }
+ // 3. 遍历 counter ,将各元素填入原数组 nums
+ let i = 0;
+ for (let num = 0; num < m + 1; num++) {
+ for (let j = 0; j < counter[num]; j++, i++) {
+ nums[i] = num;
+ }
+ }
+}
-counting_sort.ts[class]{}-[func]{countingSortNaive}
+counting_sort.ts/* 计数排序 */
+// 简单实现,无法用于排序对象
+function countingSortNaive(nums: number[]): void {
+ // 1. 统计数组最大元素 m
+ let m = 0;
+ for (const num of nums) {
+ m = Math.max(m, num);
+ }
+ // 2. 统计各数字的出现次数
+ // counter[num] 代表 num 的出现次数
+ const counter: number[] = new Array<number>(m + 1).fill(0);
+ for (const num of nums) {
+ counter[num]++;
+ }
+ // 3. 遍历 counter ,将各元素填入原数组 nums
+ let i = 0;
+ for (let num = 0; num < m + 1; num++) {
+ for (let j = 0; j < counter[num]; j++, i++) {
+ nums[i] = num;
+ }
+ }
+}
@@ -2108,11 +2150,75 @@
-counting_sort.js[class]{}-[func]{countingSort}
+counting_sort.js/* 计数排序 */
+// 完整实现,可排序对象,并且是稳定排序
+function countingSort(nums) {
+ // 1. 统计数组最大元素 m
+ let m = 0;
+ for (const num of nums) {
+ m = Math.max(m, num);
+ }
+ // 2. 统计各数字的出现次数
+ // counter[num] 代表 num 的出现次数
+ const counter = new Array(m + 1).fill(0);
+ for (const num of nums) {
+ counter[num]++;
+ }
+ // 3. 求 counter 的前缀和,将“出现次数”转换为“尾索引”
+ // 即 counter[num]-1 是 num 在 res 中最后一次出现的索引
+ for (let i = 0; i < m; i++) {
+ counter[i + 1] += counter[i];
+ }
+ // 4. 倒序遍历 nums ,将各元素填入结果数组 res
+ // 初始化数组 res 用于记录结果
+ const n = nums.length;
+ const res = new Array(n);
+ for (let i = n - 1; i >= 0; i--) {
+ const num = nums[i];
+ res[counter[num] - 1] = num; // 将 num 放置到对应索引处
+ counter[num]--; // 令前缀和自减 1 ,得到下次放置 num 的索引
+ }
+ // 使用结果数组 res 覆盖原数组 nums
+ for (let i = 0; i < n; i++) {
+ nums[i] = res[i];
+ }
+}
-counting_sort.ts[class]{}-[func]{countingSort}
+counting_sort.ts/* 计数排序 */
+// 完整实现,可排序对象,并且是稳定排序
+function countingSort(nums: number[]): void {
+ // 1. 统计数组最大元素 m
+ let m = 0;
+ for (const num of nums) {
+ m = Math.max(m, num);
+ }
+ // 2. 统计各数字的出现次数
+ // counter[num] 代表 num 的出现次数
+ const counter: number[] = new Array<number>(m + 1).fill(0);
+ for (const num of nums) {
+ counter[num]++;
+ }
+ // 3. 求 counter 的前缀和,将“出现次数”转换为“尾索引”
+ // 即 counter[num]-1 是 num 在 res 中最后一次出现的索引
+ for (let i = 0; i < m; i++) {
+ counter[i + 1] += counter[i];
+ }
+ // 4. 倒序遍历 nums ,将各元素填入结果数组 res
+ // 初始化数组 res 用于记录结果
+ const n = nums.length;
+ const res: number[] = new Array<number>(n);
+ for (let i = n - 1; i >= 0; i--) {
+ const num = nums[i];
+ res[counter[num] - 1] = num; // 将 num 放置到对应索引处
+ counter[num]--; // 令前缀和自减 1 ,得到下次放置 num 的索引
+ }
+ // 使用结果数组 res 覆盖原数组 nums
+ for (let i = 0; i < n; i++) {
+ nums[i] = res[i];
+ }
+}
diff --git a/chapter_sorting/insertion_sort.assets/insertion_operation.png b/chapter_sorting/insertion_sort.assets/insertion_operation.png
index 7a1c6dfb2..0a68d20bb 100644
Binary files a/chapter_sorting/insertion_sort.assets/insertion_operation.png and b/chapter_sorting/insertion_sort.assets/insertion_operation.png differ
diff --git a/chapter_sorting/insertion_sort.assets/insertion_sort_overview.png b/chapter_sorting/insertion_sort.assets/insertion_sort_overview.png
index 378080e25..ebb20d079 100644
Binary files a/chapter_sorting/insertion_sort.assets/insertion_sort_overview.png and b/chapter_sorting/insertion_sort.assets/insertion_sort_overview.png differ
diff --git a/chapter_sorting/intro_to_sort.assets/sorting_examples.png b/chapter_sorting/intro_to_sort.assets/sorting_examples.png
index dfcf5ce76..997d067d8 100644
Binary files a/chapter_sorting/intro_to_sort.assets/sorting_examples.png and b/chapter_sorting/intro_to_sort.assets/sorting_examples.png differ
diff --git a/chapter_sorting/merge_sort.assets/merge_sort_overview.png b/chapter_sorting/merge_sort.assets/merge_sort_overview.png
index 70add09d5..420a2b70a 100644
Binary files a/chapter_sorting/merge_sort.assets/merge_sort_overview.png and b/chapter_sorting/merge_sort.assets/merge_sort_overview.png differ
diff --git a/chapter_sorting/merge_sort.assets/merge_sort_step1.png b/chapter_sorting/merge_sort.assets/merge_sort_step1.png
index 2e2908784..5dea7ec5a 100644
Binary files a/chapter_sorting/merge_sort.assets/merge_sort_step1.png and b/chapter_sorting/merge_sort.assets/merge_sort_step1.png differ
diff --git a/chapter_sorting/merge_sort.assets/merge_sort_step10.png b/chapter_sorting/merge_sort.assets/merge_sort_step10.png
index f67b4d701..ba7e0f47f 100644
Binary files a/chapter_sorting/merge_sort.assets/merge_sort_step10.png and b/chapter_sorting/merge_sort.assets/merge_sort_step10.png differ
diff --git a/chapter_sorting/merge_sort.assets/merge_sort_step2.png b/chapter_sorting/merge_sort.assets/merge_sort_step2.png
index 926070e28..fdc31fb5e 100644
Binary files a/chapter_sorting/merge_sort.assets/merge_sort_step2.png and b/chapter_sorting/merge_sort.assets/merge_sort_step2.png differ
diff --git a/chapter_sorting/merge_sort.assets/merge_sort_step3.png b/chapter_sorting/merge_sort.assets/merge_sort_step3.png
index 78ecb46f8..0635b8379 100644
Binary files a/chapter_sorting/merge_sort.assets/merge_sort_step3.png and b/chapter_sorting/merge_sort.assets/merge_sort_step3.png differ
diff --git a/chapter_sorting/merge_sort.assets/merge_sort_step4.png b/chapter_sorting/merge_sort.assets/merge_sort_step4.png
index 22ac46519..c97e15f0a 100644
Binary files a/chapter_sorting/merge_sort.assets/merge_sort_step4.png and b/chapter_sorting/merge_sort.assets/merge_sort_step4.png differ
diff --git a/chapter_sorting/merge_sort.assets/merge_sort_step5.png b/chapter_sorting/merge_sort.assets/merge_sort_step5.png
index e89fbe226..a12eb8441 100644
Binary files a/chapter_sorting/merge_sort.assets/merge_sort_step5.png and b/chapter_sorting/merge_sort.assets/merge_sort_step5.png differ
diff --git a/chapter_sorting/merge_sort.assets/merge_sort_step6.png b/chapter_sorting/merge_sort.assets/merge_sort_step6.png
index bfa733281..c37525ecb 100644
Binary files a/chapter_sorting/merge_sort.assets/merge_sort_step6.png and b/chapter_sorting/merge_sort.assets/merge_sort_step6.png differ
diff --git a/chapter_sorting/merge_sort.assets/merge_sort_step7.png b/chapter_sorting/merge_sort.assets/merge_sort_step7.png
index 6f9b4e473..171e2790e 100644
Binary files a/chapter_sorting/merge_sort.assets/merge_sort_step7.png and b/chapter_sorting/merge_sort.assets/merge_sort_step7.png differ
diff --git a/chapter_sorting/merge_sort.assets/merge_sort_step8.png b/chapter_sorting/merge_sort.assets/merge_sort_step8.png
index 4287f0448..236fb68df 100644
Binary files a/chapter_sorting/merge_sort.assets/merge_sort_step8.png and b/chapter_sorting/merge_sort.assets/merge_sort_step8.png differ
diff --git a/chapter_sorting/merge_sort.assets/merge_sort_step9.png b/chapter_sorting/merge_sort.assets/merge_sort_step9.png
index 2d17a932e..c3c741fcf 100644
Binary files a/chapter_sorting/merge_sort.assets/merge_sort_step9.png and b/chapter_sorting/merge_sort.assets/merge_sort_step9.png differ
diff --git a/chapter_sorting/merge_sort/index.html b/chapter_sorting/merge_sort/index.html
index 0fa27d50b..ad41c2caa 100644
--- a/chapter_sorting/merge_sort/index.html
+++ b/chapter_sorting/merge_sort/index.html
@@ -1806,7 +1806,7 @@
观察发现,归并排序的递归顺序就是二叉树的「后序遍历」。
-- 后序遍历:先递归左子树、再递归右子树、最后处理根结点。
+- 后序遍历:先递归左子树、再递归右子树、最后处理根节点。
- 归并排序:先递归左子树、再递归右子树、最后处理合并。
@@ -2236,7 +2236,7 @@
11.5.3. 链表排序 *¶
归并排序有一个很特别的优势,用于排序链表时有很好的性能表现,空间复杂度可被优化至 \(O(1)\) ,这是因为:
-- 由于链表可仅通过改变指针来实现结点增删,因此“将两个短有序链表合并为一个长有序链表”无需使用额外空间,即回溯合并阶段不用像排序数组一样建立辅助数组
tmp ;
+- 由于链表可仅通过改变指针来实现节点增删,因此“将两个短有序链表合并为一个长有序链表”无需使用额外空间,即回溯合并阶段不用像排序数组一样建立辅助数组
tmp ;
- 通过使用「迭代」代替「递归划分」,可省去递归使用的栈帧空间;
diff --git a/chapter_sorting/quick_sort.assets/pivot_division_step1.png b/chapter_sorting/quick_sort.assets/pivot_division_step1.png
index dc2bf85d4..2de33457e 100644
Binary files a/chapter_sorting/quick_sort.assets/pivot_division_step1.png and b/chapter_sorting/quick_sort.assets/pivot_division_step1.png differ
diff --git a/chapter_sorting/quick_sort.assets/pivot_division_step2.png b/chapter_sorting/quick_sort.assets/pivot_division_step2.png
index ee2ca0b22..d0668ea08 100644
Binary files a/chapter_sorting/quick_sort.assets/pivot_division_step2.png and b/chapter_sorting/quick_sort.assets/pivot_division_step2.png differ
diff --git a/chapter_sorting/quick_sort.assets/pivot_division_step3.png b/chapter_sorting/quick_sort.assets/pivot_division_step3.png
index f7125e23c..53f555bf3 100644
Binary files a/chapter_sorting/quick_sort.assets/pivot_division_step3.png and b/chapter_sorting/quick_sort.assets/pivot_division_step3.png differ
diff --git a/chapter_sorting/quick_sort.assets/pivot_division_step4.png b/chapter_sorting/quick_sort.assets/pivot_division_step4.png
index 4629b9ec7..b962d868f 100644
Binary files a/chapter_sorting/quick_sort.assets/pivot_division_step4.png and b/chapter_sorting/quick_sort.assets/pivot_division_step4.png differ
diff --git a/chapter_sorting/quick_sort.assets/pivot_division_step5.png b/chapter_sorting/quick_sort.assets/pivot_division_step5.png
index 257340697..f805171e1 100644
Binary files a/chapter_sorting/quick_sort.assets/pivot_division_step5.png and b/chapter_sorting/quick_sort.assets/pivot_division_step5.png differ
diff --git a/chapter_sorting/quick_sort.assets/pivot_division_step6.png b/chapter_sorting/quick_sort.assets/pivot_division_step6.png
index 9edce956a..ef1c5192c 100644
Binary files a/chapter_sorting/quick_sort.assets/pivot_division_step6.png and b/chapter_sorting/quick_sort.assets/pivot_division_step6.png differ
diff --git a/chapter_sorting/quick_sort.assets/pivot_division_step7.png b/chapter_sorting/quick_sort.assets/pivot_division_step7.png
index 3efdd6c0d..cb18664b5 100644
Binary files a/chapter_sorting/quick_sort.assets/pivot_division_step7.png and b/chapter_sorting/quick_sort.assets/pivot_division_step7.png differ
diff --git a/chapter_sorting/quick_sort.assets/pivot_division_step8.png b/chapter_sorting/quick_sort.assets/pivot_division_step8.png
index 206cb81f0..38e7365f1 100644
Binary files a/chapter_sorting/quick_sort.assets/pivot_division_step8.png and b/chapter_sorting/quick_sort.assets/pivot_division_step8.png differ
diff --git a/chapter_sorting/quick_sort.assets/pivot_division_step9.png b/chapter_sorting/quick_sort.assets/pivot_division_step9.png
index 706fd1547..c0e950d44 100644
Binary files a/chapter_sorting/quick_sort.assets/pivot_division_step9.png and b/chapter_sorting/quick_sort.assets/pivot_division_step9.png differ
diff --git a/chapter_sorting/quick_sort.assets/quick_sort_overview.png b/chapter_sorting/quick_sort.assets/quick_sort_overview.png
index db3c7b752..39787f0ac 100644
Binary files a/chapter_sorting/quick_sort.assets/quick_sort_overview.png and b/chapter_sorting/quick_sort.assets/quick_sort_overview.png differ
diff --git a/chapter_sorting/radix_sort.assets/radix_sort_overview.png b/chapter_sorting/radix_sort.assets/radix_sort_overview.png
index a88b53ada..c92b184c5 100644
Binary files a/chapter_sorting/radix_sort.assets/radix_sort_overview.png and b/chapter_sorting/radix_sort.assets/radix_sort_overview.png differ
diff --git a/chapter_sorting/radix_sort/index.html b/chapter_sorting/radix_sort/index.html
index e67977810..369a5dcaf 100644
--- a/chapter_sorting/radix_sort/index.html
+++ b/chapter_sorting/radix_sort/index.html
@@ -1958,19 +1958,113 @@ x_k = \lfloor\frac{x}{d^{k-1}}\rfloor \mod d
-radix_sort.js[class]{}-[func]{digit}
-
-[class]{}-[func]{countingSortDigit}
-
-[class]{}-[func]{radixSort}
+radix_sort.js/* 获取元素 num 的第 k 位,其中 exp = 10^(k-1) */
+function digit(num, exp) {
+ // 传入 exp 而非 k 可以避免在此重复执行昂贵的次方计算
+ return Math.floor(num / exp) % 10;
+}
+
+/* 计数排序(根据 nums 第 k 位排序) */
+function countingSortDigit(nums, exp) {
+ // 十进制的位范围为 0~9 ,因此需要长度为 10 的桶
+ const counter = new Array(10).fill(0);
+ const n = nums.length;
+ // 统计 0~9 各数字的出现次数
+ for (let i = 0; i < n; i++) {
+ const d = digit(nums[i], exp); // 获取 nums[i] 第 k 位,记为 d
+ counter[d]++; // 统计数字 d 的出现次数
+ }
+ // 求前缀和,将“出现个数”转换为“数组索引”
+ for (let i = 1; i < 10; i++) {
+ counter[i] += counter[i - 1];
+ }
+ // 倒序遍历,根据桶内统计结果,将各元素填入 res
+ const res = new Array(n).fill(0);
+ for (let i = n - 1; i >= 0; i--) {
+ const d = digit(nums[i], exp);
+ const j = counter[d] - 1; // 获取 d 在数组中的索引 j
+ res[j] = nums[i]; // 将当前元素填入索引 j
+ counter[d]--; // 将 d 的数量减 1
+ }
+ // 使用结果覆盖原数组 nums
+ for (let i = 0; i < n; i++) {
+ nums[i] = res[i];
+ }
+}
+
+/* 基数排序 */
+function radixSort(nums) {
+ // 获取数组的最大元素,用于判断最大位数
+ let m = Number.MIN_VALUE;
+ for (const num of nums) {
+ if (num > m) {
+ m = num;
+ }
+ }
+ // 按照从低位到高位的顺序遍历
+ for (let exp = 1; exp <= m; exp *= 10) {
+ // 对数组元素的第 k 位执行计数排序
+ // k = 1 -> exp = 1
+ // k = 2 -> exp = 10
+ // 即 exp = 10^(k-1)
+ countingSortDigit(nums, exp);
+ }
+}
-radix_sort.ts[class]{}-[func]{digit}
-
-[class]{}-[func]{countingSortDigit}
-
-[class]{}-[func]{radixSort}
+radix_sort.ts/* 获取元素 num 的第 k 位,其中 exp = 10^(k-1) */
+function digit(num: number, exp: number): number {
+ // 传入 exp 而非 k 可以避免在此重复执行昂贵的次方计算
+ return Math.floor(num / exp) % 10;
+}
+
+/* 计数排序(根据 nums 第 k 位排序) */
+function countingSortDigit(nums: number[], exp: number): void {
+ // 十进制的位范围为 0~9 ,因此需要长度为 10 的桶
+ const counter = new Array(10).fill(0);
+ const n = nums.length;
+ // 统计 0~9 各数字的出现次数
+ for (let i = 0; i < n; i++) {
+ const d = digit(nums[i], exp); // 获取 nums[i] 第 k 位,记为 d
+ counter[d]++; // 统计数字 d 的出现次数
+ }
+ // 求前缀和,将“出现个数”转换为“数组索引”
+ for (let i = 1; i < 10; i++) {
+ counter[i] += counter[i - 1];
+ }
+ // 倒序遍历,根据桶内统计结果,将各元素填入 res
+ const res = new Array(n).fill(0);
+ for (let i = n - 1; i >= 0; i--) {
+ const d = digit(nums[i], exp);
+ const j = counter[d] - 1; // 获取 d 在数组中的索引 j
+ res[j] = nums[i]; // 将当前元素填入索引 j
+ counter[d]--; // 将 d 的数量减 1
+ }
+ // 使用结果覆盖原数组 nums
+ for (let i = 0; i < n; i++) {
+ nums[i] = res[i];
+ }
+}
+
+/* 基数排序 */
+function radixSort(nums: number[]): void {
+ // 获取数组的最大元素,用于判断最大位数
+ let m = Number.MIN_VALUE;
+ for (const num of nums) {
+ if (num > m) {
+ m = num;
+ }
+ }
+ // 按照从低位到高位的顺序遍历
+ for (let exp = 1; exp <= m; exp *= 10) {
+ // 对数组元素的第 k 位执行计数排序
+ // k = 1 -> exp = 1
+ // k = 2 -> exp = 10
+ // 即 exp = 10^(k-1)
+ countingSortDigit(nums, exp);
+ }
+}
diff --git a/chapter_sorting/summary.assets/sorting_algorithms_comparison.png b/chapter_sorting/summary.assets/sorting_algorithms_comparison.png
index 5c11896a4..2ff2877c7 100644
Binary files a/chapter_sorting/summary.assets/sorting_algorithms_comparison.png and b/chapter_sorting/summary.assets/sorting_algorithms_comparison.png differ
diff --git a/chapter_stack_and_queue/deque.assets/array_deque.png b/chapter_stack_and_queue/deque.assets/array_deque.png
index 3ef1c2889..8cec65215 100644
Binary files a/chapter_stack_and_queue/deque.assets/array_deque.png and b/chapter_stack_and_queue/deque.assets/array_deque.png differ
diff --git a/chapter_stack_and_queue/deque.assets/array_deque_pop_first.png b/chapter_stack_and_queue/deque.assets/array_deque_pop_first.png
index 8137d0163..2d89de3dc 100644
Binary files a/chapter_stack_and_queue/deque.assets/array_deque_pop_first.png and b/chapter_stack_and_queue/deque.assets/array_deque_pop_first.png differ
diff --git a/chapter_stack_and_queue/deque.assets/array_deque_pop_last.png b/chapter_stack_and_queue/deque.assets/array_deque_pop_last.png
index 7c759310f..a31edef88 100644
Binary files a/chapter_stack_and_queue/deque.assets/array_deque_pop_last.png and b/chapter_stack_and_queue/deque.assets/array_deque_pop_last.png differ
diff --git a/chapter_stack_and_queue/deque.assets/array_deque_push_first.png b/chapter_stack_and_queue/deque.assets/array_deque_push_first.png
index 04120335e..cfb02a3cc 100644
Binary files a/chapter_stack_and_queue/deque.assets/array_deque_push_first.png and b/chapter_stack_and_queue/deque.assets/array_deque_push_first.png differ
diff --git a/chapter_stack_and_queue/deque.assets/array_deque_push_last.png b/chapter_stack_and_queue/deque.assets/array_deque_push_last.png
index 33816de8e..ef071a3c8 100644
Binary files a/chapter_stack_and_queue/deque.assets/array_deque_push_last.png and b/chapter_stack_and_queue/deque.assets/array_deque_push_last.png differ
diff --git a/chapter_stack_and_queue/deque.assets/deque_operations.png b/chapter_stack_and_queue/deque.assets/deque_operations.png
index da8e03c07..b8c7ba483 100644
Binary files a/chapter_stack_and_queue/deque.assets/deque_operations.png and b/chapter_stack_and_queue/deque.assets/deque_operations.png differ
diff --git a/chapter_stack_and_queue/deque.assets/linkedlist_deque.png b/chapter_stack_and_queue/deque.assets/linkedlist_deque.png
index 407bd6205..d03a62154 100644
Binary files a/chapter_stack_and_queue/deque.assets/linkedlist_deque.png and b/chapter_stack_and_queue/deque.assets/linkedlist_deque.png differ
diff --git a/chapter_stack_and_queue/deque.assets/linkedlist_deque_pop_first.png b/chapter_stack_and_queue/deque.assets/linkedlist_deque_pop_first.png
index 22bb86308..d5da2e724 100644
Binary files a/chapter_stack_and_queue/deque.assets/linkedlist_deque_pop_first.png and b/chapter_stack_and_queue/deque.assets/linkedlist_deque_pop_first.png differ
diff --git a/chapter_stack_and_queue/deque.assets/linkedlist_deque_pop_last.png b/chapter_stack_and_queue/deque.assets/linkedlist_deque_pop_last.png
index f05b270fd..39c53bfcd 100644
Binary files a/chapter_stack_and_queue/deque.assets/linkedlist_deque_pop_last.png and b/chapter_stack_and_queue/deque.assets/linkedlist_deque_pop_last.png differ
diff --git a/chapter_stack_and_queue/deque.assets/linkedlist_deque_push_first.png b/chapter_stack_and_queue/deque.assets/linkedlist_deque_push_first.png
index 2f0d0e531..a170d5c85 100644
Binary files a/chapter_stack_and_queue/deque.assets/linkedlist_deque_push_first.png and b/chapter_stack_and_queue/deque.assets/linkedlist_deque_push_first.png differ
diff --git a/chapter_stack_and_queue/deque.assets/linkedlist_deque_push_last.png b/chapter_stack_and_queue/deque.assets/linkedlist_deque_push_last.png
index 811cb97c7..4d1e710e2 100644
Binary files a/chapter_stack_and_queue/deque.assets/linkedlist_deque_push_last.png and b/chapter_stack_and_queue/deque.assets/linkedlist_deque_push_last.png differ
diff --git a/chapter_stack_and_queue/deque/index.html b/chapter_stack_and_queue/deque/index.html
index 18ca53b4e..7aeeeb5f8 100644
--- a/chapter_stack_and_queue/deque/index.html
+++ b/chapter_stack_and_queue/deque/index.html
@@ -2091,9 +2091,9 @@
5.3.2. 双向队列实现 *¶
与队列类似,双向队列同样可以使用链表或数组来实现。
基于双向链表的实现¶
-回忆上节内容,由于可以方便地删除链表头结点(对应出队操作),以及在链表尾结点后添加新结点(对应入队操作),因此我们使用普通单向链表来实现队列。
+回忆上节内容,由于可以方便地删除链表头节点(对应出队操作),以及在链表尾节点后添加新节点(对应入队操作),因此我们使用普通单向链表来实现队列。
而双向队列的头部和尾部都可以执行入队与出队操作,换言之,双向队列的操作是“首尾对称”的,也需要实现另一个对称方向的操作。因此,双向队列需要使用「双向链表」来实现。
-我们将双向链表的头结点和尾结点分别看作双向队列的队首和队尾,并且实现在两端都能添加与删除结点。
+我们将双向链表的头节点和尾节点分别看作双向队列的队首和队尾,并且实现在两端都能添加与删除节点。
@@ -2117,11 +2117,11 @@
-linkedlist_deque.java/* 双向链表结点 */
+linkedlist_deque.java/* 双向链表节点 */
class ListNode {
- int val; // 结点值
- ListNode next; // 后继结点引用(指针)
- ListNode prev; // 前驱结点引用(指针)
+ int val; // 节点值
+ ListNode next; // 后继节点引用(指针)
+ ListNode prev; // 前驱节点引用(指针)
ListNode(int val) {
this.val = val;
prev = next = null;
@@ -2130,7 +2130,7 @@
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
- private ListNode front, rear; // 头结点 front ,尾结点 rear
+ private ListNode front, rear; // 头节点 front ,尾节点 rear
private int queSize = 0; // 双向队列的长度
public LinkedListDeque() {
@@ -2158,13 +2158,13 @@
// 将 node 添加至链表头部
front.prev = node;
node.next = front;
- front = node; // 更新头结点
+ front = node; // 更新头节点
// 队尾入队操作
} else {
// 将 node 添加至链表尾部
rear.next = node;
node.prev = rear;
- rear = node; // 更新尾结点
+ rear = node; // 更新尾节点
}
queSize++; // 更新队列长度
}
@@ -2187,24 +2187,24 @@
int val;
// 队首出队操作
if (isFront) {
- val = front.val; // 暂存头结点值
- // 删除头结点
+ val = front.val; // 暂存头节点值
+ // 删除头节点
ListNode fNext = front.next;
if (fNext != null) {
fNext.prev = null;
front.next = null;
}
- front = fNext; // 更新头结点
+ front = fNext; // 更新头节点
// 队尾出队操作
} else {
- val = rear.val; // 暂存尾结点值
- // 删除尾结点
+ val = rear.val; // 暂存尾节点值
+ // 删除尾节点
ListNode rPrev = rear.prev;
if (rPrev != null) {
rPrev.next = null;
rear.prev = null;
}
- rear = rPrev; // 更新尾结点
+ rear = rPrev; // 更新尾节点
}
queSize--; // 更新队列长度
return val;
@@ -2244,18 +2244,18 @@
-linkedlist_deque.cpp/* 双向链表结点 */
+linkedlist_deque.cpp/* 双向链表节点 */
struct DoublyListNode {
- int val; // 结点值
- DoublyListNode *next; // 后继结点指针
- DoublyListNode *prev; // 前驱结点指针
+ int val; // 节点值
+ DoublyListNode *next; // 后继节点指针
+ DoublyListNode *prev; // 前驱节点指针
DoublyListNode(int val) : val(val), prev(nullptr), next(nullptr) {}
};
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
private:
- DoublyListNode *front, *rear; // 头结点 front ,尾结点 rear
+ DoublyListNode *front, *rear; // 头节点 front ,尾节点 rear
int queSize = 0; // 双向队列的长度
public:
@@ -2264,7 +2264,7 @@
/* 析构方法 */
~LinkedListDeque() {
- // 遍历链表删除结点,释放内存
+ // 遍历链表删除节点,释放内存
DoublyListNode *pre, *cur = front;
while (cur != nullptr) {
pre = cur;
@@ -2294,13 +2294,13 @@
// 将 node 添加至链表头部
front->prev = node;
node->next = front;
- front = node; // 更新头结点
+ front = node; // 更新头节点
// 队尾入队操作
} else {
// 将 node 添加至链表尾部
rear->next = node;
node->prev = rear;
- rear = node; // 更新尾结点
+ rear = node; // 更新尾节点
}
queSize++; // 更新队列长度
}
@@ -2323,26 +2323,26 @@
int val;
// 队首出队操作
if (isFront) {
- val = front->val; // 暂存头结点值
- // 删除头结点
+ val = front->val; // 暂存头节点值
+ // 删除头节点
DoublyListNode *fNext = front->next;
if (fNext != nullptr) {
fNext->prev = nullptr;
front->next = nullptr;
delete front;
}
- front = fNext; // 更新头结点
+ front = fNext; // 更新头节点
// 队尾出队操作
} else {
- val = rear->val; // 暂存尾结点值
- // 删除尾结点
+ val = rear->val; // 暂存尾节点值
+ // 删除尾节点
DoublyListNode *rPrev = rear->prev;
if (rPrev != nullptr) {
rPrev->next = nullptr;
rear->prev = nullptr;
delete rear;
}
- rear = rPrev; // 更新尾结点
+ rear = rPrev; // 更新尾节点
}
queSize--; // 更新队列长度
return val;
@@ -2383,19 +2383,19 @@
linkedlist_deque.pyclass ListNode:
- """ 双向链表结点 """
+ """ 双向链表节点 """
def __init__(self, val: int) -> None:
""" 构造方法 """
self.val: int = val
- self.next: ListNode | None = None # 后继结点引用(指针)
- self.prev: ListNode | None = None # 前驱结点引用(指针)
+ self.next: ListNode | None = None # 后继节点引用(指针)
+ self.prev: ListNode | None = None # 前驱节点引用(指针)
class LinkedListDeque:
""" 基于双向链表实现的双向队列 """
def __init__(self) -> None:
""" 构造方法 """
- self.front: ListNode | None = None # 头结点 front
- self.rear: ListNode | None = None # 尾结点 rear
+ self.front: ListNode | None = None # 头节点 front
+ self.rear: ListNode | None = None # 尾节点 rear
self.__size: int = 0 # 双向队列的长度
def size(self) -> int:
@@ -2417,13 +2417,13 @@
# 将 node 添加至链表头部
self.front.prev = node
node.next = self.front
- self.front = node # 更新头结点
+ self.front = node # 更新头节点
# 队尾入队操作
else:
# 将 node 添加至链表尾部
self.rear.next = node
node.prev = self.rear
- self.rear = node # 更新尾结点
+ self.rear = node # 更新尾节点
self.__size += 1 # 更新队列长度
def push_first(self, num: int) -> None:
@@ -2441,22 +2441,22 @@
return None
# 队首出队操作
if is_front:
- val: int = self.front.val # 暂存头结点值
- # 删除头结点
+ val: int = self.front.val # 暂存头节点值
+ # 删除头节点
fnext: ListNode | None = self.front.next
if fnext != None:
fnext.prev = None
self.front.next = None
- self.front = fnext # 更新头结点
+ self.front = fnext # 更新头节点
# 队尾出队操作
else:
- val: int = self.rear.val # 暂存尾结点值
- # 删除尾结点
+ val: int = self.rear.val # 暂存尾节点值
+ # 删除尾节点
rprev: ListNode | None = self.rear.prev
if rprev != None:
rprev.next = None
self.rear.prev = None
- self.rear = rprev # 更新尾结点
+ self.rear = rprev # 更新尾节点
self.__size -= 1 # 更新队列长度
return val
@@ -2565,11 +2565,11 @@
-linkedlist_deque.js/* 双向链表结点 */
+linkedlist_deque.js/* 双向链表节点 */
class ListNode {
- prev; // 前驱结点引用 (指针)
- next; // 后继结点引用 (指针)
- val; // 结点值
+ prev; // 前驱节点引用 (指针)
+ next; // 后继节点引用 (指针)
+ val; // 节点值
constructor(val) {
this.val = val;
@@ -2580,8 +2580,8 @@
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
- #front; // 头结点 front
- #rear; // 尾结点 rear
+ #front; // 头节点 front
+ #rear; // 尾节点 rear
#queSize; // 双向队列的长度
constructor() {
@@ -2601,7 +2601,7 @@
// 将 node 添加至链表尾部
this.#rear.next = node;
node.prev = this.#rear;
- this.#rear = node; // 更新尾结点
+ this.#rear = node; // 更新尾节点
}
this.#queSize++;
}
@@ -2617,7 +2617,7 @@
// 将 node 添加至链表头部
this.#front.prev = node;
node.next = this.#front;
- this.#front = node; // 更新头结点
+ this.#front = node; // 更新头节点
}
this.#queSize++;
}
@@ -2627,14 +2627,14 @@
if (this.#queSize === 0) {
return null;
}
- const value = this.#rear.val; // 存储尾结点值
- // 删除尾结点
+ const value = this.#rear.val; // 存储尾节点值
+ // 删除尾节点
let temp = this.#rear.prev;
if (temp !== null) {
temp.next = null;
this.#rear.prev = null;
}
- this.#rear = temp; // 更新尾结点
+ this.#rear = temp; // 更新尾节点
this.#queSize--;
return value;
}
@@ -2644,14 +2644,14 @@
if (this.#queSize === 0) {
return null;
}
- const value = this.#front.val; // 存储尾结点值
- // 删除头结点
+ const value = this.#front.val; // 存储尾节点值
+ // 删除头节点
let temp = this.#front.next;
if (temp !== null) {
temp.prev = null;
this.#front.next = null;
}
- this.#front = temp; // 更新头结点
+ this.#front = temp; // 更新头节点
this.#queSize--;
return value;
}
@@ -2690,11 +2690,11 @@
-linkedlist_deque.ts/* 双向链表结点 */
+linkedlist_deque.ts/* 双向链表节点 */
class ListNode {
- prev: ListNode; // 前驱结点引用 (指针)
- next: ListNode; // 后继结点引用 (指针)
- val: number; // 结点值
+ prev: ListNode; // 前驱节点引用 (指针)
+ next: ListNode; // 后继节点引用 (指针)
+ val: number; // 节点值
constructor(val: number) {
this.val = val;
@@ -2705,8 +2705,8 @@
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
- private front: ListNode; // 头结点 front
- private rear: ListNode; // 尾结点 rear
+ private front: ListNode; // 头节点 front
+ private rear: ListNode; // 尾节点 rear
private queSize: number; // 双向队列的长度
constructor() {
@@ -2726,7 +2726,7 @@
// 将 node 添加至链表尾部
this.rear.next = node;
node.prev = this.rear;
- this.rear = node; // 更新尾结点
+ this.rear = node; // 更新尾节点
}
this.queSize++;
}
@@ -2742,7 +2742,7 @@
// 将 node 添加至链表头部
this.front.prev = node;
node.next = this.front;
- this.front = node; // 更新头结点
+ this.front = node; // 更新头节点
}
this.queSize++;
}
@@ -2752,14 +2752,14 @@
if (this.queSize === 0) {
return null;
}
- const value: number = this.rear.val; // 存储尾结点值
- // 删除尾结点
+ const value: number = this.rear.val; // 存储尾节点值
+ // 删除尾节点
let temp: ListNode = this.rear.prev;
if (temp !== null) {
temp.next = null;
this.rear.prev = null;
}
- this.rear = temp; // 更新尾结点
+ this.rear = temp; // 更新尾节点
this.queSize--;
return value;
}
@@ -2769,14 +2769,14 @@
if (this.queSize === 0) {
return null;
}
- const value: number = this.front.val; // 存储尾结点值
- // 删除头结点
+ const value: number = this.front.val; // 存储尾节点值
+ // 删除头节点
let temp: ListNode = this.front.next;
if (temp !== null) {
temp.prev = null;
this.front.next = null;
}
- this.front = temp; // 更新头结点
+ this.front = temp; // 更新头节点
this.queSize--;
return value;
}
@@ -2827,11 +2827,11 @@
-linkedlist_deque.swift/* 双向链表结点 */
+linkedlist_deque.swift/* 双向链表节点 */
class ListNode {
- var val: Int // 结点值
- var next: ListNode? // 后继结点引用(指针)
- var prev: ListNode? // 前驱结点引用(指针)
+ var val: Int // 节点值
+ var next: ListNode? // 后继节点引用(指针)
+ var prev: ListNode? // 前驱节点引用(指针)
init(val: Int) {
self.val = val
@@ -2840,8 +2840,8 @@
/* 基于双向链表实现的双向队列 */
class LinkedListDeque {
- private var front: ListNode? // 头结点 front
- private var rear: ListNode? // 尾结点 rear
+ private var front: ListNode? // 头节点 front
+ private var rear: ListNode? // 尾节点 rear
private var queSize: Int // 双向队列的长度
init() {
@@ -2871,14 +2871,14 @@
// 将 node 添加至链表头部
front?.prev = node
node.next = front
- front = node // 更新头结点
+ front = node // 更新头节点
}
// 队尾入队操作
else {
// 将 node 添加至链表尾部
rear?.next = node
node.prev = rear
- rear = node // 更新尾结点
+ rear = node // 更新尾节点
}
queSize += 1 // 更新队列长度
}
@@ -2901,25 +2901,25 @@
let val: Int
// 队首出队操作
if isFront {
- val = front!.val // 暂存头结点值
- // 删除头结点
+ val = front!.val // 暂存头节点值
+ // 删除头节点
let fNext = front?.next
if fNext != nil {
fNext?.prev = nil
front?.next = nil
}
- front = fNext // 更新头结点
+ front = fNext // 更新头节点
}
// 队尾出队操作
else {
- val = rear!.val // 暂存尾结点值
- // 删除尾结点
+ val = rear!.val // 暂存尾节点值
+ // 删除尾节点
let rPrev = rear?.prev
if rPrev != nil {
rPrev?.next = nil
rear?.prev = nil
}
- rear = rPrev // 更新尾结点
+ rear = rPrev // 更新尾节点
}
queSize -= 1 // 更新队列长度
return val
@@ -2959,14 +2959,14 @@
-linkedlist_deque.zig// 双向链表结点
+linkedlist_deque.zig// 双向链表节点
fn ListNode(comptime T: type) type {
return struct {
const Self = @This();
- val: T = undefined, // 结点值
- next: ?*Self = null, // 后继结点引用(指针)
- prev: ?*Self = null, // 前驱结点引用(指针)
+ val: T = undefined, // 节点值
+ next: ?*Self = null, // 后继节点引用(指针)
+ prev: ?*Self = null, // 前驱节点引用(指针)
// Initialize a list node with specific value
pub fn init(self: *Self, x: i32) void {
@@ -2982,8 +2982,8 @@
return struct {
const Self = @This();
- front: ?*ListNode(T) = null, // 头结点 front
- rear: ?*ListNode(T) = null, // 尾结点 rear
+ front: ?*ListNode(T) = null, // 头节点 front
+ rear: ?*ListNode(T) = null, // 尾节点 rear
que_size: usize = 0, // 双向队列的长度
mem_arena: ?std.heap.ArenaAllocator = null,
mem_allocator: std.mem.Allocator = undefined, // 内存分配器
@@ -3028,13 +3028,13 @@
// 将 node 添加至链表头部
self.front.?.prev = node;
node.next = self.front;
- self.front = node; // 更新头结点
+ self.front = node; // 更新头节点
// 队尾入队操作
} else {
// 将 node 添加至链表尾部
self.rear.?.next = node;
node.prev = self.rear;
- self.rear = node; // 更新尾结点
+ self.rear = node; // 更新尾节点
}
self.que_size += 1; // 更新队列长度
}
@@ -3055,24 +3055,24 @@
var val: T = undefined;
// 队首出队操作
if (is_front) {
- val = self.front.?.val; // 暂存头结点值
- // 删除头结点
+ val = self.front.?.val; // 暂存头节点值
+ // 删除头节点
var fNext = self.front.?.next;
if (fNext != null) {
fNext.?.prev = null;
self.front.?.next = null;
}
- self.front = fNext; // 更新头结点
+ self.front = fNext; // 更新头节点
// 队尾出队操作
} else {
- val = self.rear.?.val; // 暂存尾结点值
- // 删除尾结点
+ val = self.rear.?.val; // 暂存尾节点值
+ // 删除尾节点
var rPrev = self.rear.?.prev;
if (rPrev != null) {
rPrev.?.next = null;
self.rear.?.prev = null;
}
- self.rear = rPrev; // 更新尾结点
+ self.rear = rPrev; // 更新尾节点
}
self.que_size -= 1; // 更新队列长度
return val;
diff --git a/chapter_stack_and_queue/queue.assets/array_queue.png b/chapter_stack_and_queue/queue.assets/array_queue.png
index e4e17d039..3ee9812cf 100644
Binary files a/chapter_stack_and_queue/queue.assets/array_queue.png and b/chapter_stack_and_queue/queue.assets/array_queue.png differ
diff --git a/chapter_stack_and_queue/queue.assets/array_queue_pop.png b/chapter_stack_and_queue/queue.assets/array_queue_pop.png
index 3cfb3b421..b3540fdb8 100644
Binary files a/chapter_stack_and_queue/queue.assets/array_queue_pop.png and b/chapter_stack_and_queue/queue.assets/array_queue_pop.png differ
diff --git a/chapter_stack_and_queue/queue.assets/array_queue_push.png b/chapter_stack_and_queue/queue.assets/array_queue_push.png
index b1926ab7e..d4c661d4a 100644
Binary files a/chapter_stack_and_queue/queue.assets/array_queue_push.png and b/chapter_stack_and_queue/queue.assets/array_queue_push.png differ
diff --git a/chapter_stack_and_queue/queue.assets/linkedlist_queue.png b/chapter_stack_and_queue/queue.assets/linkedlist_queue.png
index 160d781b2..a3e0e2ed1 100644
Binary files a/chapter_stack_and_queue/queue.assets/linkedlist_queue.png and b/chapter_stack_and_queue/queue.assets/linkedlist_queue.png differ
diff --git a/chapter_stack_and_queue/queue.assets/linkedlist_queue_pop.png b/chapter_stack_and_queue/queue.assets/linkedlist_queue_pop.png
index f964e460a..9b8d5481d 100644
Binary files a/chapter_stack_and_queue/queue.assets/linkedlist_queue_pop.png and b/chapter_stack_and_queue/queue.assets/linkedlist_queue_pop.png differ
diff --git a/chapter_stack_and_queue/queue.assets/linkedlist_queue_push.png b/chapter_stack_and_queue/queue.assets/linkedlist_queue_push.png
index baebb145b..f80bb7e74 100644
Binary files a/chapter_stack_and_queue/queue.assets/linkedlist_queue_push.png and b/chapter_stack_and_queue/queue.assets/linkedlist_queue_push.png differ
diff --git a/chapter_stack_and_queue/queue.assets/queue_operations.png b/chapter_stack_and_queue/queue.assets/queue_operations.png
index 80bb031c3..b57372d90 100644
Binary files a/chapter_stack_and_queue/queue.assets/queue_operations.png and b/chapter_stack_and_queue/queue.assets/queue_operations.png differ
diff --git a/chapter_stack_and_queue/queue/index.html b/chapter_stack_and_queue/queue/index.html
index a2d42b619..b567e5016 100644
--- a/chapter_stack_and_queue/queue/index.html
+++ b/chapter_stack_and_queue/queue/index.html
@@ -2061,7 +2061,7 @@
5.2.2. 队列实现¶
队列需要一种可以在一端添加,并在另一端删除的数据结构,也可以使用链表或数组来实现。
基于链表的实现¶
-我们将链表的「头结点」和「尾结点」分别看作是队首和队尾,并规定队尾只可添加结点,队首只可删除结点。
+我们将链表的「头节点」和「尾节点」分别看作是队首和队尾,并规定队尾只可添加节点,队首只可删除节点。
@@ -2081,7 +2081,7 @@
linkedlist_queue.java/* 基于链表实现的队列 */
class LinkedListQueue {
- private ListNode front, rear; // 头结点 front ,尾结点 rear
+ private ListNode front, rear; // 头节点 front ,尾节点 rear
private int queSize = 0;
public LinkedListQueue() {
@@ -2101,13 +2101,13 @@
/* 入队 */
public void push(int num) {
- // 尾结点后添加 num
+ // 尾节点后添加 num
ListNode node = new ListNode(num);
- // 如果队列为空,则令头、尾结点都指向该结点
+ // 如果队列为空,则令头、尾节点都指向该节点
if (front == null) {
front = node;
rear = node;
- // 如果队列不为空,则将该结点添加到尾结点后
+ // 如果队列不为空,则将该节点添加到尾节点后
} else {
rear.next = node;
rear = node;
@@ -2118,7 +2118,7 @@
/* 出队 */
public int pop() {
int num = peek();
- // 删除头结点
+ // 删除头节点
front = front.next;
queSize--;
return num;
@@ -2148,7 +2148,7 @@
linkedlist_queue.cpp/* 基于链表实现的队列 */
class LinkedListQueue {
private:
- ListNode *front, *rear; // 头结点 front ,尾结点 rear
+ ListNode *front, *rear; // 头节点 front ,尾节点 rear
int queSize;
public:
@@ -2159,7 +2159,7 @@
}
~LinkedListQueue() {
- // 遍历链表删除结点,释放内存
+ // 遍历链表删除节点,释放内存
freeMemoryLinkedList(front);
}
@@ -2175,14 +2175,14 @@
/* 入队 */
void push(int num) {
- // 尾结点后添加 num
+ // 尾节点后添加 num
ListNode* node = new ListNode(num);
- // 如果队列为空,则令头、尾结点都指向该结点
+ // 如果队列为空,则令头、尾节点都指向该节点
if (front == nullptr) {
front = node;
rear = node;
}
- // 如果队列不为空,则将该结点添加到尾结点后
+ // 如果队列不为空,则将该节点添加到尾节点后
else {
rear->next = node;
rear = node;
@@ -2193,7 +2193,7 @@
/* 出队 */
void pop() {
int num = peek();
- // 删除头结点
+ // 删除头节点
ListNode *tmp = front;
front = front->next;
// 释放内存
@@ -2226,8 +2226,8 @@
""" 基于链表实现的队列 """
def __init__(self):
""" 构造方法 """
- self.__front: ListNode | None = None # 头结点 front
- self.__rear: ListNode | None = None # 尾结点 rear
+ self.__front: ListNode | None = None # 头节点 front
+ self.__rear: ListNode | None = None # 尾节点 rear
self.__size: int = 0
def size(self) -> int:
@@ -2240,13 +2240,13 @@
def push(self, num: int) -> None:
""" 入队 """
- # 尾结点后添加 num
+ # 尾节点后添加 num
node = ListNode(num)
- # 如果队列为空,则令头、尾结点都指向该结点
+ # 如果队列为空,则令头、尾节点都指向该节点
if self.__front is None:
self.__front = node
self.__rear = node
- # 如果队列不为空,则将该结点添加到尾结点后
+ # 如果队列不为空,则将该节点添加到尾节点后
else:
self.__rear.next = node
self.__rear = node
@@ -2255,7 +2255,7 @@
def pop(self) -> int:
""" 出队 """
num = self.peek()
- # 删除头结点
+ # 删除头节点
self.__front = self.__front.next
self.__size -= 1
return num
@@ -2334,8 +2334,8 @@
linkedlist_queue.js/* 基于链表实现的队列 */
class LinkedListQueue {
- #front; // 头结点 #front
- #rear; // 尾结点 #rear
+ #front; // 头节点 #front
+ #rear; // 尾节点 #rear
#queSize = 0;
constructor() {
@@ -2355,13 +2355,13 @@
/* 入队 */
push(num) {
- // 尾结点后添加 num
+ // 尾节点后添加 num
const node = new ListNode(num);
- // 如果队列为空,则令头、尾结点都指向该结点
+ // 如果队列为空,则令头、尾节点都指向该节点
if (!this.#front) {
this.#front = node;
this.#rear = node;
- // 如果队列不为空,则将该结点添加到尾结点后
+ // 如果队列不为空,则将该节点添加到尾节点后
} else {
this.#rear.next = node;
this.#rear = node;
@@ -2372,7 +2372,7 @@
/* 出队 */
pop() {
const num = this.peek();
- // 删除头结点
+ // 删除头节点
this.#front = this.#front.next;
this.#queSize--;
return num;
@@ -2401,8 +2401,8 @@
linkedlist_queue.ts/* 基于链表实现的队列 */
class LinkedListQueue {
- private front: ListNode | null; // 头结点 front
- private rear: ListNode | null; // 尾结点 rear
+ private front: ListNode | null; // 头节点 front
+ private rear: ListNode | null; // 尾节点 rear
private queSize: number = 0;
constructor() {
@@ -2422,13 +2422,13 @@
/* 入队 */
push(num: number): void {
- // 尾结点后添加 num
+ // 尾节点后添加 num
const node = new ListNode(num);
- // 如果队列为空,则令头、尾结点都指向该结点
+ // 如果队列为空,则令头、尾节点都指向该节点
if (!this.front) {
this.front = node;
this.rear = node;
- // 如果队列不为空,则将该结点添加到尾结点后
+ // 如果队列不为空,则将该节点添加到尾节点后
} else {
this.rear!.next = node;
this.rear = node;
@@ -2440,7 +2440,7 @@
pop(): number {
const num = this.peek();
if (!this.front) throw new Error('队列为空');
- // 删除头结点
+ // 删除头节点
this.front = this.front.next;
this.queSize--;
return num;
@@ -2473,7 +2473,7 @@
linkedlist_queue.cs/* 基于链表实现的队列 */
class LinkedListQueue
{
- private ListNode? front, rear; // 头结点 front ,尾结点 rear
+ private ListNode? front, rear; // 头节点 front ,尾节点 rear
private int queSize = 0;
public LinkedListQueue()
@@ -2497,14 +2497,14 @@
/* 入队 */
public void push(int num)
{
- // 尾结点后添加 num
+ // 尾节点后添加 num
ListNode node = new ListNode(num);
- // 如果队列为空,则令头、尾结点都指向该结点
+ // 如果队列为空,则令头、尾节点都指向该节点
if (front == null)
{
front = node;
rear = node;
- // 如果队列不为空,则将该结点添加到尾结点后
+ // 如果队列不为空,则将该节点添加到尾节点后
}
else if (rear != null)
{
@@ -2518,7 +2518,7 @@
public int pop()
{
int num = peek();
- // 删除头结点
+ // 删除头节点
front = front?.next;
queSize--;
return num;
@@ -2553,8 +2553,8 @@
linkedlist_queue.swift/* 基于链表实现的队列 */
class LinkedListQueue {
- private var front: ListNode? // 头结点
- private var rear: ListNode? // 尾结点
+ private var front: ListNode? // 头节点
+ private var rear: ListNode? // 尾节点
private var _size = 0
init() {}
@@ -2571,14 +2571,14 @@
/* 入队 */
func push(num: Int) {
- // 尾结点后添加 num
+ // 尾节点后添加 num
let node = ListNode(x: num)
- // 如果队列为空,则令头、尾结点都指向该结点
+ // 如果队列为空,则令头、尾节点都指向该节点
if front == nil {
front = node
rear = node
}
- // 如果队列不为空,则将该结点添加到尾结点后
+ // 如果队列不为空,则将该节点添加到尾节点后
else {
rear?.next = node
rear = node
@@ -2590,7 +2590,7 @@
@discardableResult
func pop() -> Int {
let num = peek()
- // 删除头结点
+ // 删除头节点
front = front?.next
_size -= 1
return num
@@ -2623,8 +2623,8 @@
return struct {
const Self = @This();
- front: ?*inc.ListNode(T) = null, // 头结点 front
- rear: ?*inc.ListNode(T) = null, // 尾结点 rear
+ front: ?*inc.ListNode(T) = null, // 头节点 front
+ rear: ?*inc.ListNode(T) = null, // 尾节点 rear
que_size: usize = 0, // 队列的长度
mem_arena: ?std.heap.ArenaAllocator = null,
mem_allocator: std.mem.Allocator = undefined, // 内存分配器
@@ -2664,14 +2664,14 @@
// 入队
pub fn push(self: *Self, num: T) !void {
- // 尾结点后添加 num
+ // 尾节点后添加 num
var node = try self.mem_allocator.create(inc.ListNode(T));
node.init(num);
- // 如果队列为空,则令头、尾结点都指向该结点
+ // 如果队列为空,则令头、尾节点都指向该节点
if (self.front == null) {
self.front = node;
self.rear = node;
- // 如果队列不为空,则将该结点添加到尾结点后
+ // 如果队列不为空,则将该节点添加到尾节点后
} else {
self.rear.?.next = node;
self.rear = node;
@@ -2682,7 +2682,7 @@
// 出队
pub fn pop(self: *Self) T {
var num = self.peek();
- // 删除头结点
+ // 删除头节点
self.front = self.front.?.next;
self.que_size -= 1;
return num;
diff --git a/chapter_stack_and_queue/stack.assets/array_stack.png b/chapter_stack_and_queue/stack.assets/array_stack.png
index 9667bba62..c422b92f3 100644
Binary files a/chapter_stack_and_queue/stack.assets/array_stack.png and b/chapter_stack_and_queue/stack.assets/array_stack.png differ
diff --git a/chapter_stack_and_queue/stack.assets/array_stack_pop.png b/chapter_stack_and_queue/stack.assets/array_stack_pop.png
index e846ae814..3377d1629 100644
Binary files a/chapter_stack_and_queue/stack.assets/array_stack_pop.png and b/chapter_stack_and_queue/stack.assets/array_stack_pop.png differ
diff --git a/chapter_stack_and_queue/stack.assets/array_stack_push.png b/chapter_stack_and_queue/stack.assets/array_stack_push.png
index ba8a11f2d..79cd24256 100644
Binary files a/chapter_stack_and_queue/stack.assets/array_stack_push.png and b/chapter_stack_and_queue/stack.assets/array_stack_push.png differ
diff --git a/chapter_stack_and_queue/stack.assets/linkedlist_stack.png b/chapter_stack_and_queue/stack.assets/linkedlist_stack.png
index f11493474..03cbda289 100644
Binary files a/chapter_stack_and_queue/stack.assets/linkedlist_stack.png and b/chapter_stack_and_queue/stack.assets/linkedlist_stack.png differ
diff --git a/chapter_stack_and_queue/stack.assets/linkedlist_stack_pop.png b/chapter_stack_and_queue/stack.assets/linkedlist_stack_pop.png
index fc7babba2..45c617091 100644
Binary files a/chapter_stack_and_queue/stack.assets/linkedlist_stack_pop.png and b/chapter_stack_and_queue/stack.assets/linkedlist_stack_pop.png differ
diff --git a/chapter_stack_and_queue/stack.assets/linkedlist_stack_push.png b/chapter_stack_and_queue/stack.assets/linkedlist_stack_push.png
index 71bc925eb..7df0c77e6 100644
Binary files a/chapter_stack_and_queue/stack.assets/linkedlist_stack_push.png and b/chapter_stack_and_queue/stack.assets/linkedlist_stack_push.png differ
diff --git a/chapter_stack_and_queue/stack.assets/stack_operations.png b/chapter_stack_and_queue/stack.assets/stack_operations.png
index 945d0fe8e..2173d9440 100644
Binary files a/chapter_stack_and_queue/stack.assets/stack_operations.png and b/chapter_stack_and_queue/stack.assets/stack_operations.png differ
diff --git a/chapter_stack_and_queue/stack/index.html b/chapter_stack_and_queue/stack/index.html
index 6c2930b43..1701e84a7 100644
--- a/chapter_stack_and_queue/stack/index.html
+++ b/chapter_stack_and_queue/stack/index.html
@@ -2113,8 +2113,8 @@
为了更加清晰地了解栈的运行机制,接下来我们来自己动手实现一个栈类。
栈规定元素是先入后出的,因此我们只能在栈顶添加或删除元素。然而,数组或链表都可以在任意位置添加删除元素,因此 栈可被看作是一种受约束的数组或链表。换言之,我们可以“屏蔽”数组或链表的部分无关操作,使之对外的表现逻辑符合栈的规定即可。
基于链表的实现¶
-使用「链表」实现栈时,将链表的头结点看作栈顶,将尾结点看作栈底。
-对于入栈操作,将元素插入到链表头部即可,这种结点添加方式被称为“头插法”。而对于出栈操作,则将头结点从链表中删除即可。
+使用「链表」实现栈时,将链表的头节点看作栈顶,将尾节点看作栈底。
+对于入栈操作,将元素插入到链表头部即可,这种节点添加方式被称为“头插法”。而对于出栈操作,则将头节点从链表中删除即可。
@@ -2134,7 +2134,7 @@
linkedlist_stack.java/* 基于链表实现的栈 */
class LinkedListStack {
- private ListNode stackPeek; // 将头结点作为栈顶
+ private ListNode stackPeek; // 将头节点作为栈顶
private int stkSize = 0; // 栈的长度
public LinkedListStack() {
@@ -2191,7 +2191,7 @@
linkedlist_stack.cpp/* 基于链表实现的栈 */
class LinkedListStack {
private:
- ListNode* stackTop; // 将头结点作为栈顶
+ ListNode* stackTop; // 将头节点作为栈顶
int stkSize; // 栈的长度
public:
@@ -2201,7 +2201,7 @@
}
~LinkedListStack() {
- // 遍历链表删除结点,释放内存
+ // 遍历链表删除节点,释放内存
freeMemoryLinkedList(stackTop);
}
@@ -2357,7 +2357,7 @@
linkedlist_stack.js/* 基于链表实现的栈 */
class LinkedListStack {
- #stackPeek; // 将头结点作为栈顶
+ #stackPeek; // 将头节点作为栈顶
#stkSize = 0; // 栈的长度
constructor() {
@@ -2413,7 +2413,7 @@
linkedlist_stack.ts/* 基于链表实现的栈 */
class LinkedListStack {
- private stackPeek: ListNode | null; // 将头结点作为栈顶
+ private stackPeek: ListNode | null; // 将头节点作为栈顶
private stkSize: number = 0; // 栈的长度
constructor() {
@@ -2474,7 +2474,7 @@
linkedlist_stack.cs/* 基于链表实现的栈 */
class LinkedListStack
{
- private ListNode? stackPeek; // 将头结点作为栈顶
+ private ListNode? stackPeek; // 将头节点作为栈顶
private int stkSize = 0; // 栈的长度
public LinkedListStack()
@@ -2544,7 +2544,7 @@
linkedlist_stack.swift/* 基于链表实现的栈 */
class LinkedListStack {
- private var _peek: ListNode? // 将头结点作为栈顶
+ private var _peek: ListNode? // 将头节点作为栈顶
private var _size = 0 // 栈的长度
init() {}
@@ -2603,7 +2603,7 @@
return struct {
const Self = @This();
- stack_top: ?*inc.ListNode(T) = null, // 将头结点作为栈顶
+ stack_top: ?*inc.ListNode(T) = null, // 将头节点作为栈顶
stk_size: usize = 0, // 栈的长度
mem_arena: ?std.heap.ArenaAllocator = null,
mem_allocator: std.mem.Allocator = undefined, // 内存分配器
@@ -3125,7 +3125,7 @@
两种实现都支持栈定义中的各项操作,数组实现额外支持随机访问,但这已经超出栈的定义范畴,一般不会用到。
时间效率¶
在数组(列表)实现中,入栈与出栈操作都是在预先分配好的连续内存中操作,具有很好的缓存本地性,效率很好。然而,如果入栈时超出数组容量,则会触发扩容机制,那么该次入栈操作的时间复杂度为 \(O(n)\) 。
-在链表实现中,链表的扩容非常灵活,不存在上述数组扩容时变慢的问题。然而,入栈操作需要初始化结点对象并修改指针,因而效率不如数组。进一步地思考,如果入栈元素不是 int 而是结点对象,那么就可以省去初始化步骤,从而提升效率。
+在链表实现中,链表的扩容非常灵活,不存在上述数组扩容时变慢的问题。然而,入栈操作需要初始化节点对象并修改指针,因而效率不如数组。进一步地思考,如果入栈元素不是 int 而是节点对象,那么就可以省去初始化步骤,从而提升效率。
综上所述,当入栈与出栈操作的元素是基本数据类型(例如 int , double )时,则结论如下:
- 数组实现的栈在触发扩容时会变慢,但由于扩容是低频操作,因此 总体效率更高;
@@ -3133,7 +3133,7 @@
空间效率¶
在初始化列表时,系统会给列表分配“初始容量”,该容量可能超过我们的需求。并且扩容机制一般是按照特定倍率(比如 2 倍)进行扩容,扩容后的容量也可能超出我们的需求。因此,数组实现栈会造成一定的空间浪费。
-当然,由于结点需要额外存储指针,因此 链表结点比数组元素占用更大。
+当然,由于节点需要额外存储指针,因此 链表节点比数组元素占用更大。
综上,我们不能简单地确定哪种实现更加省内存,需要 case-by-case 地分析。
5.1.4. 栈典型应用¶
diff --git a/chapter_stack_and_queue/summary/index.html b/chapter_stack_and_queue/summary/index.html
index 5d3febd69..afa014a1a 100644
--- a/chapter_stack_and_queue/summary/index.html
+++ b/chapter_stack_and_queue/summary/index.html
@@ -1683,7 +1683,7 @@
- 栈是一种遵循先入后出的数据结构,可以使用数组或链表实现。
- 在时间效率方面,栈的数组实现具有更好的平均效率,但扩容时会导致单次入栈操作的时间复杂度劣化至 \(O(n)\) 。相对地,栈的链表实现具有更加稳定的效率表现。
-- 在空间效率方面,栈的数组实现会造成一定空间浪费,然而链表结点比数组元素占用内存更大。
+- 在空间效率方面,栈的数组实现会造成一定空间浪费,然而链表节点比数组元素占用内存更大。
- 队列是一种遵循先入先出的数据结构,可以使用数组或链表实现。对于两种实现的时间效率与空间效率对比,与上述栈的结论相同。
- 双向队列的两端都可以添加与删除元素。
diff --git a/chapter_tree/avl_tree.assets/avltree_degradation_from_inserting_node.png b/chapter_tree/avl_tree.assets/avltree_degradation_from_inserting_node.png
index c28d5b747..15080808f 100644
Binary files a/chapter_tree/avl_tree.assets/avltree_degradation_from_inserting_node.png and b/chapter_tree/avl_tree.assets/avltree_degradation_from_inserting_node.png differ
diff --git a/chapter_tree/avl_tree.assets/avltree_degradation_from_removing_node.png b/chapter_tree/avl_tree.assets/avltree_degradation_from_removing_node.png
index 19ecc6fe7..1ba22fd8e 100644
Binary files a/chapter_tree/avl_tree.assets/avltree_degradation_from_removing_node.png and b/chapter_tree/avl_tree.assets/avltree_degradation_from_removing_node.png differ
diff --git a/chapter_tree/avl_tree.assets/avltree_left_right_rotate.png b/chapter_tree/avl_tree.assets/avltree_left_right_rotate.png
index 5b37e5980..02afb13fe 100644
Binary files a/chapter_tree/avl_tree.assets/avltree_left_right_rotate.png and b/chapter_tree/avl_tree.assets/avltree_left_right_rotate.png differ
diff --git a/chapter_tree/avl_tree.assets/avltree_left_rotate.png b/chapter_tree/avl_tree.assets/avltree_left_rotate.png
index 199a7d454..0b4842bd8 100644
Binary files a/chapter_tree/avl_tree.assets/avltree_left_rotate.png and b/chapter_tree/avl_tree.assets/avltree_left_rotate.png differ
diff --git a/chapter_tree/avl_tree.assets/avltree_left_rotate_with_grandchild.png b/chapter_tree/avl_tree.assets/avltree_left_rotate_with_grandchild.png
index cd6cdf3dc..7c690fe29 100644
Binary files a/chapter_tree/avl_tree.assets/avltree_left_rotate_with_grandchild.png and b/chapter_tree/avl_tree.assets/avltree_left_rotate_with_grandchild.png differ
diff --git a/chapter_tree/avl_tree.assets/avltree_right_left_rotate.png b/chapter_tree/avl_tree.assets/avltree_right_left_rotate.png
index 846f1fceb..ed18f6513 100644
Binary files a/chapter_tree/avl_tree.assets/avltree_right_left_rotate.png and b/chapter_tree/avl_tree.assets/avltree_right_left_rotate.png differ
diff --git a/chapter_tree/avl_tree.assets/avltree_right_rotate_step1.png b/chapter_tree/avl_tree.assets/avltree_right_rotate_step1.png
index a010a8e24..dcee29fed 100644
Binary files a/chapter_tree/avl_tree.assets/avltree_right_rotate_step1.png and b/chapter_tree/avl_tree.assets/avltree_right_rotate_step1.png differ
diff --git a/chapter_tree/avl_tree.assets/avltree_right_rotate_step2.png b/chapter_tree/avl_tree.assets/avltree_right_rotate_step2.png
index 462bd5764..fcc6ba873 100644
Binary files a/chapter_tree/avl_tree.assets/avltree_right_rotate_step2.png and b/chapter_tree/avl_tree.assets/avltree_right_rotate_step2.png differ
diff --git a/chapter_tree/avl_tree.assets/avltree_right_rotate_step3.png b/chapter_tree/avl_tree.assets/avltree_right_rotate_step3.png
index 0080b2184..f0fce12ca 100644
Binary files a/chapter_tree/avl_tree.assets/avltree_right_rotate_step3.png and b/chapter_tree/avl_tree.assets/avltree_right_rotate_step3.png differ
diff --git a/chapter_tree/avl_tree.assets/avltree_right_rotate_step4.png b/chapter_tree/avl_tree.assets/avltree_right_rotate_step4.png
index e3a5509c3..41180815e 100644
Binary files a/chapter_tree/avl_tree.assets/avltree_right_rotate_step4.png and b/chapter_tree/avl_tree.assets/avltree_right_rotate_step4.png differ
diff --git a/chapter_tree/avl_tree.assets/avltree_right_rotate_with_grandchild.png b/chapter_tree/avl_tree.assets/avltree_right_rotate_with_grandchild.png
index 65a894743..28273df7a 100644
Binary files a/chapter_tree/avl_tree.assets/avltree_right_rotate_with_grandchild.png and b/chapter_tree/avl_tree.assets/avltree_right_rotate_with_grandchild.png differ
diff --git a/chapter_tree/avl_tree.assets/avltree_rotation_cases.png b/chapter_tree/avl_tree.assets/avltree_rotation_cases.png
index 2fb56b036..522683a93 100644
Binary files a/chapter_tree/avl_tree.assets/avltree_rotation_cases.png and b/chapter_tree/avl_tree.assets/avltree_rotation_cases.png differ
diff --git a/chapter_tree/avl_tree/index.html b/chapter_tree/avl_tree/index.html
index f36d3bcfa..56c2958dd 100644
--- a/chapter_tree/avl_tree/index.html
+++ b/chapter_tree/avl_tree/index.html
@@ -1049,14 +1049,14 @@
-
- 结点高度
+ 节点高度
-
- 结点平衡因子
+ 节点平衡因子
@@ -1124,21 +1124,21 @@
-
- 插入结点
+ 插入节点
-
- 删除结点
+ 删除节点
-
- 查找结点
+ 查找节点
@@ -1814,14 +1814,14 @@
-
- 结点高度
+ 节点高度
-
- 结点平衡因子
+ 节点平衡因子
@@ -1889,21 +1889,21 @@
-
- 插入结点
+ 插入节点
-
- 删除结点
+ 删除节点
-
- 查找结点
+ 查找节点
@@ -1945,71 +1945,71 @@
7.4. AVL 树 *¶
在「二叉搜索树」章节中提到,在进行多次插入与删除操作后,二叉搜索树可能会退化为链表。此时所有操作的时间复杂度都会由 \(O(\log n)\) 劣化至 \(O(n)\) 。
-如下图所示,执行两步删除结点后,该二叉搜索树就会退化为链表。
-
- Fig. AVL 树在删除结点后发生退化
+如下图所示,执行两步删除节点后,该二叉搜索树就会退化为链表。
+
+ Fig. AVL 树在删除节点后发生退化
-再比如,在以下完美二叉树中插入两个结点后,树严重向左偏斜,查找操作的时间复杂度也随之发生劣化。
-
- Fig. AVL 树在插入结点后发生退化
+再比如,在以下完美二叉树中插入两个节点后,树严重向左偏斜,查找操作的时间复杂度也随之发生劣化。
+
+ Fig. AVL 树在插入节点后发生退化
-G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorithm for the organization of information" 中提出了「AVL 树」。论文中描述了一系列操作,使得在不断添加与删除结点后,AVL 树仍然不会发生退化,进而使得各种操作的时间复杂度均能保持在 \(O(\log n)\) 级别。
+G. M. Adelson-Velsky 和 E. M. Landis 在其 1962 年发表的论文 "An algorithm for the organization of information" 中提出了「AVL 树」。论文中描述了一系列操作,使得在不断添加与删除节点后,AVL 树仍然不会发生退化,进而使得各种操作的时间复杂度均能保持在 \(O(\log n)\) 级别。
换言之,在频繁增删查改的使用场景中,AVL 树可始终保持很高的数据增删查改效率,具有很好的应用价值。
7.4.1. AVL 树常见术语¶
「AVL 树」既是「二叉搜索树」又是「平衡二叉树」,同时满足这两种二叉树的所有性质,因此又被称为「平衡二叉搜索树」。
-结点高度¶
-在 AVL 树的操作中,需要获取结点「高度 Height」,所以给 AVL 树的结点类添加 height 变量。
+节点高度¶
+在 AVL 树的操作中,需要获取节点「高度 Height」,所以给 AVL 树的节点类添加 height 变量。
-/* AVL 树结点类 */
+/* AVL 树节点类 */
class TreeNode {
- public int val; // 结点值
- public int height; // 结点高度
- public TreeNode left; // 左子结点
- public TreeNode right; // 右子结点
+ public int val; // 节点值
+ public int height; // 节点高度
+ public TreeNode left; // 左子节点
+ public TreeNode right; // 右子节点
public TreeNode(int x) { val = x; }
}
-
-""" AVL 树结点类 """
+""" AVL 树节点类 """
class TreeNode:
def __init__(self, val: int):
- self.val: int = val # 结点值
- self.height: int = 0 # 结点高度
- self.left: Optional[TreeNode] = None # 左子结点引用
- self.right: Optional[TreeNode] = None # 右子结点引用
+ self.val: int = val # 节点值
+ self.height: int = 0 # 节点高度
+ self.left: Optional[TreeNode] = None # 左子节点引用
+ self.right: Optional[TreeNode] = None # 右子节点引用
-
class TreeNode {
- val; // 结点值
- height; //结点高度
- left; // 左子结点指针
- right; // 右子结点指针
+ val; // 节点值
+ height; //节点高度
+ left; // 左子节点指针
+ right; // 右子节点指针
constructor(val, left, right, height) {
this.val = val === undefined ? 0 : val;
this.height = height === undefined ? 0 : height;
@@ -2021,10 +2021,10 @@
class TreeNode {
- val: number; // 结点值
- height: number; // 结点高度
- left: TreeNode | null; // 左子结点指针
- right: TreeNode | null; // 右子结点指针
+ val: number; // 节点值
+ height: number; // 节点高度
+ left: TreeNode | null; // 左子节点指针
+ right: TreeNode | null; // 右子节点指针
constructor(val?: number, height?: number, left?: TreeNode | null, right?: TreeNode | null) {
this.val = val === undefined ? 0 : val;
this.height = height === undefined ? 0 : height;
@@ -2039,23 +2039,23 @@
-/* AVL 树结点类 */
+/* AVL 树节点类 */
class TreeNode {
- public int val; // 结点值
- public int height; // 结点高度
- public TreeNode? left; // 左子结点
- public TreeNode? right; // 右子结点
+ public int val; // 节点值
+ public int height; // 节点高度
+ public TreeNode? left; // 左子节点
+ public TreeNode? right; // 右子节点
public TreeNode(int x) { val = x; }
}
-「结点高度」是最远叶结点到该结点的距离,即走过的「边」的数量。需要特别注意,叶结点的高度为 0 ,空结点的高度为 -1。我们封装两个工具函数,分别用于获取与更新结点的高度。
+「节点高度」是最远叶节点到该节点的距离,即走过的「边」的数量。需要特别注意,叶节点的高度为 0 ,空节点的高度为 -1。我们封装两个工具函数,分别用于获取与更新节点的高度。
-avl_tree.java/* 获取结点高度 */
+avl_tree.java/* 获取节点高度 */
int height(TreeNode node) {
- // 空结点高度为 -1 ,叶结点高度为 0
+ // 空节点高度为 -1 ,叶节点高度为 0
return node == null ? -1 : node.height;
}
-/* 更新结点高度 */
+/* 更新节点高度 */
void updateHeight(TreeNode node) {
- // 结点高度等于最高子树高度 + 1
+ // 节点高度等于最高子树高度 + 1
node.height = Math.max(height(node.left), height(node.right)) + 1;
}
-avl_tree.cpp/* 获取结点高度 */
+avl_tree.cpp/* 获取节点高度 */
int height(TreeNode* node) {
- // 空结点高度为 -1 ,叶结点高度为 0
+ // 空节点高度为 -1 ,叶节点高度为 0
return node == nullptr ? -1 : node->height;
}
-/* 更新结点高度 */
+/* 更新节点高度 */
void updateHeight(TreeNode* node) {
- // 结点高度等于最高子树高度 + 1
+ // 节点高度等于最高子树高度 + 1
node->height = max(height(node->left), height(node->right)) + 1;
}
avl_tree.pydef height(self, node: TreeNode | None) -> int:
- """ 获取结点高度 """
- # 空结点高度为 -1 ,叶结点高度为 0
+ """ 获取节点高度 """
+ # 空节点高度为 -1 ,叶节点高度为 0
if node is not None:
return node.height
return -1
def __update_height(self, node: TreeNode | None):
- """ 更新结点高度 """
- # 结点高度等于最高子树高度 + 1
+ """ 更新节点高度 """
+ # 节点高度等于最高子树高度 + 1
node.height = max([self.height(node.left), self.height(node.right)]) + 1
-avl_tree.go/* 获取结点高度 */
+avl_tree.go/* 获取节点高度 */
func (t *aVLTree) height(node *TreeNode) int {
- // 空结点高度为 -1 ,叶结点高度为 0
+ // 空节点高度为 -1 ,叶节点高度为 0
if node != nil {
return node.Height
}
return -1
}
-/* 更新结点高度 */
+/* 更新节点高度 */
func (t *aVLTree) updateHeight(node *TreeNode) {
lh := t.height(node.Left)
rh := t.height(node.Right)
- // 结点高度等于最高子树高度 + 1
+ // 节点高度等于最高子树高度 + 1
if lh > rh {
node.Height = lh + 1
} else {
@@ -2139,29 +2139,29 @@
-avl_tree.js/* 获取结点高度 */
+avl_tree.js/* 获取节点高度 */
height(node) {
- // 空结点高度为 -1 ,叶结点高度为 0
+ // 空节点高度为 -1 ,叶节点高度为 0
return node === null ? -1 : node.height;
}
-/* 更新结点高度 */
+/* 更新节点高度 */
#updateHeight(node) {
- // 结点高度等于最高子树高度 + 1
+ // 节点高度等于最高子树高度 + 1
node.height = Math.max(this.height(node.left), this.height(node.right)) + 1;
}
-avl_tree.ts/* 获取结点高度 */
+avl_tree.ts/* 获取节点高度 */
height(node: TreeNode): number {
- // 空结点高度为 -1 ,叶结点高度为 0
+ // 空节点高度为 -1 ,叶节点高度为 0
return node === null ? -1 : node.height;
}
-/* 更新结点高度 */
+/* 更新节点高度 */
updateHeight(node: TreeNode): void {
- // 结点高度等于最高子树高度 + 1
+ // 节点高度等于最高子树高度 + 1
node.height = Math.max(this.height(node.left), this.height(node.right)) + 1;
}
@@ -2173,62 +2173,62 @@
-avl_tree.cs/* 获取结点高度 */
+avl_tree.cs/* 获取节点高度 */
int height(TreeNode? node)
{
- // 空结点高度为 -1 ,叶结点高度为 0
+ // 空节点高度为 -1 ,叶节点高度为 0
return node == null ? -1 : node.height;
}
-/* 更新结点高度 */
+/* 更新节点高度 */
void updateHeight(TreeNode node)
{
- // 结点高度等于最高子树高度 + 1
+ // 节点高度等于最高子树高度 + 1
node.height = Math.Max(height(node.left), height(node.right)) + 1;
}
-avl_tree.swift/* 获取结点高度 */
+avl_tree.swift/* 获取节点高度 */
func height(node: TreeNode?) -> Int {
- // 空结点高度为 -1 ,叶结点高度为 0
+ // 空节点高度为 -1 ,叶节点高度为 0
node == nil ? -1 : node!.height
}
-/* 更新结点高度 */
+/* 更新节点高度 */
func updateHeight(node: TreeNode?) {
- // 结点高度等于最高子树高度 + 1
+ // 节点高度等于最高子树高度 + 1
node?.height = max(height(node: node?.left), height(node: node?.right)) + 1
}