This commit is contained in:
krahets 2023-09-17 01:11:33 +08:00
parent 221bec3ea3
commit fca420d938
12 changed files with 64 additions and 15 deletions

View file

@ -45,8 +45,8 @@ comments: true
### 8.   Swift 环境
1. 下载并安装 [Swift](https://www.swift.org/download/)。
2. 在 VSCode 的插件市场中搜索 `swift` ,安装 [Swift for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=sswg.swift-lang)。
1. 下载并安装 [Swift](https://www.swift.org/download/)
2. 在 VSCode 的插件市场中搜索 `swift` ,安装 [Swift for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=sswg.swift-lang)
### 9.   Dart 环境
@ -55,5 +55,5 @@ comments: true
### 10.   Rust 环境
1. 下载并安装 [Rust](https://www.rust-lang.org/tools/install)。
2. 在 VSCode 的插件市场中搜索 `rust` ,安装 [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)。
1. 下载并安装 [Rust](https://www.rust-lang.org/tools/install)
2. 在 VSCode 的插件市场中搜索 `rust` ,安装 [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer)

View file

@ -861,7 +861,7 @@ comments: true
为了加深对列表工作原理的理解,我们尝试实现一个简易版列表,包括以下三个重点设计。
- **初始容量**:选取一个合理的数组初始容量。在本示例中,我们选择 10 作为初始容量。
- **数量记录**:声明一个变量 size用于记录列表当前元素数量并随着元素插入和删除实时更新。根据此变量我们可以定位列表尾部以及判断是否需要扩容。
- **数量记录**:声明一个变量 `size` ,用于记录列表当前元素数量,并随着元素插入和删除实时更新。根据此变量,我们可以定位列表尾部,以及判断是否需要扩容。
- **扩容机制**:若插入元素时列表容量已满,则需要进行扩容。首先根据扩容倍数创建一个更大的数组,再将当前数组的所有元素依次移动至新数组。在本示例中,我们规定每次将数组扩容至之前的 2 倍。
=== "Python"

View file

@ -471,7 +471,7 @@ comments: true
除此之外,我们还对代码进行了以下两项优化。
- 在开启搜索前,先将数组 `nums` 排序。在遍历所有选择时,**当子集和超过 `target` 时直接结束循环**,因为后边的元素更大,其子集和都一定会超过 `target`
- 省去元素和变量 `total`**通过在 `target` 上执行减法来统计元素和**,当 `target` 等于 $0$ 时记录解。
- 省去元素和变量 `total` **通过在 `target` 上执行减法来统计元素和**,当 `target` 等于 $0$ 时记录解。
=== "Python"

View file

@ -7,7 +7,7 @@ comments: true
运行时间可以直观且准确地反映算法的效率。如果我们想要准确预估一段代码的运行时间,应该如何操作呢?
1. **确定运行平台**,包括硬件配置、编程语言、系统环境等,这些因素都会影响代码的运行效率。
2. **评估各种计算操作所需的运行时间**,例如加法操作 `+` 需要 1 ns乘法操作 `*` 需要 10 ns打印操作 `print()` 需要 5 ns 等。
2. **评估各种计算操作所需的运行时间**,例如加法操作 `+` 需要 1 ns ,乘法操作 `*` 需要 10 ns ,打印操作 `print()` 需要 5 ns 等。
3. **统计代码中所有的计算操作**,并将所有操作的执行时间求和,从而得到运行时间。
例如在以下代码中,输入数据大小为 $n$
@ -3260,7 +3260,7 @@ $$
```c title="worst_best_time_complexity.c"
/* 生成一个数组,元素为 { 1, 2, ..., n },顺序被打乱 */
int *randomNumbers(int n) {
// 分配堆区内存创建一维可变长数组数组中元素数量为n元素类型为int
// 分配堆区内存(创建一维可变长数组:数组中元素数量为 n ,元素类型为 int
int *nums = (int *)malloc(n * sizeof(int));
// 生成数组 nums = { 1, 2, 3, ..., n }
for (int i = 0; i < n; i++) {

View file

@ -94,7 +94,7 @@ $$
## 3.3.2 &nbsp; 浮点数编码
细心的你可能会发现:`int` 和 `float` 长度相同,都是 4 bytes但为什么 `float` 的取值范围远大于 `int` ?这非常反直觉,因为按理说 `float` 需要表示小数,取值范围应该变小才对。
细心的你可能会发现:`int` 和 `float` 长度相同,都是 4 bytes ,但为什么 `float` 的取值范围远大于 `int` ?这非常反直觉,因为按理说 `float` 需要表示小数,取值范围应该变小才对。
实际上,**这是因为浮点数 `float` 采用了不同的表示方式**。记一个 32-bit 长度的二进制数为:

View file

@ -86,7 +86,7 @@ $$
**第三步:确定边界条件和状态转移顺序**
在本题中,处在首行的状态只能向右转移,首列状态只能向下转移,因此首行 $i = 0$ 和首列 $j = 0$ 是边界条件。
在本题中,首行的状态只能从其左边的状态得来,首列的状态只能从其上边的状态得来,因此首行 $i = 0$ 和首列 $j = 0$ 是边界条件。
如图 14-13 所示,由于每个格子是由其左方格子和上方格子转移而来,因此我们使用采用循环来遍历矩阵,外循环遍历各行、内循环遍历各列。

View file

@ -1164,7 +1164,7 @@ comments: true
def __init__(self, edges: list[list[Vertex]]):
"""构造方法"""
# 邻接表key: 顶点value该顶点的所有邻接顶点
self.adj_list = dict[Vertex, Vertex]()
self.adj_list = dict[Vertex, list[Vertex]]()
# 添加所有顶点和边
for edge in edges:
self.add_vertex(edge[0])

View file

@ -207,7 +207,7 @@ comments: true
```javascript title="top_k.js"
/* 基于堆查找数组中最大的 k 个元素 */
function topKHeap(nums, k) {
// 使用大顶堆 MaxHeap对数组 nums 取相反数
// 使用大顶堆 MaxHeap ,对数组 nums 取相反数
const invertedNums = nums.map((num) => -num);
// 将数组的前 k 个元素入堆
const heap = new MaxHeap(invertedNums.slice(0, k));

View file

@ -41,7 +41,7 @@ comments: true
- 感谢我在公司的导师李汐博士,在一次畅谈中您鼓励我“快行动起来”,坚定了我写这本书的决心。
- 感谢我的女朋友泡泡作为本书的首位读者,从算法小白的角度提出许多宝贵建议,使得本书更适合新手阅读。
- 感谢腾宝、琦宝、飞宝为本书起了一个富有创意的名字,唤起大家写下第一行代码 "Hello World!" 的美好回忆。
- 感谢苏潼为本书设计了精美的封面和 LOGO并在我的强迫症下多次耐心修改。
- 感谢苏潼为本书设计了精美的封面和 LOGO ,并在我的强迫症下多次耐心修改。
- 感谢 @squidfunk 提供的写作排版建议,以及他开发的开源文档主题 [Material-for-MkDocs](https://github.com/squidfunk/mkdocs-material/tree/master) 。
在写作过程中,我阅读了许多关于数据结构与算法的教材和文章。这些作品为本书提供了优秀的范本,确保了本书内容的准确性与品质。在此感谢所有老师和前辈们的杰出贡献!

View file

@ -311,7 +311,33 @@ comments: true
=== "Rust"
```rust title="deque.rs"
/* 初始化双向队列 */
let mut deque: VecDeque<u32> = VecDeque::new();
/* 元素入队 */
deque.push_back(2); // 添加至队尾
deque.push_back(5);
deque.push_back(4);
deque.push_front(3); // 添加至队首
deque.push_front(1);
/* 访问元素 */
if let Some(front) = deque.front() { // 队首元素
}
if let Some(rear) = deque.back() { // 队尾元素
}
/* 元素出队 */
if let Some(pop_front) = deque.pop_front() { // 队首元素出队
}
if let Some(pop_rear) = deque.pop_back() { // 队尾元素出队
}
/* 获取双向队列的长度 */
let size = deque.len();
/* 判断双向队列是否为空 */
let is_empty = deque.is_empty();
```
=== "C"
@ -1394,7 +1420,7 @@ comments: true
void push(int num, bool isFront) {
final ListNode node = ListNode(num);
if (isEmpty()) {
// 若链表为空,则令 _front_rear 都指向 node
// 若链表为空,则令 _front_rear 都指向 node
_front = _rear = node;
} else if (isFront) {
// 队首入队操作

View file

@ -278,7 +278,30 @@ comments: true
=== "Rust"
```rust title="queue.rs"
/* 初始化双向队列 */
// 在 Rust 中使用双向队列作为普通队列来使用
let mut deque: VecDeque<u32> = VecDeque::new();
/* 元素入队 */
deque.push_back(1);
deque.push_back(3);
deque.push_back(2);
deque.push_back(5);
deque.push_back(4);
/* 访问队首元素 */
if let Some(front) = deque.front() {
}
/* 元素出队 */
if let Some(pop) = deque.pop_front() {
}
/* 获取队列的长度 */
let size = deque.len();
/* 判断队列是否为空 */
let is_empty = deque.is_empty();
```
=== "C"

View file

@ -4,7 +4,7 @@ comments: true
# 7.5 &nbsp; AVL 树 *
在二叉搜索树章节中,我们提到了在多次插入和删除操作后,二叉搜索树可能退化为链表。这种情况下,所有操作的时间复杂度将从 $O(\log n)$ 恶化为 $O(n)$。
在二叉搜索树章节中,我们提到了在多次插入和删除操作后,二叉搜索树可能退化为链表。这种情况下,所有操作的时间复杂度将从 $O(\log n)$ 恶化为 $O(n)$
如图 7-24 所示,经过两次删除节点操作,这个二叉搜索树便会退化为链表。