Release Rust code to documents. (#656)

This commit is contained in:
Yudong Jin
2023-07-26 11:00:53 +08:00
committed by GitHub
parent 60162f6fa8
commit 027bdd6510
61 changed files with 1155 additions and 145 deletions

View File

@ -102,6 +102,12 @@
[class]{}-[func]{bubbleSort}
```
=== "Rust"
```rust title="bubble_sort.rs"
[class]{}-[func]{bubble_sort}
```
## 效率优化
我们发现,如果某轮“冒泡”中没有执行任何交换操作,说明数组已经完成排序,可直接返回结果。因此,可以增加一个标志位 `flag` 来监测这种情况,一旦出现就立即返回。
@ -174,6 +180,12 @@
[class]{}-[func]{bubbleSortWithFlag}
```
=== "Rust"
```rust title="bubble_sort.rs"
[class]{}-[func]{bubble_sort_with_flag}
```
## 算法特性
- **时间复杂度为 $O(n^2)$ 、自适应排序** :各轮“冒泡”遍历的数组长度依次为 $n - 1$ , $n - 2$ , $\cdots$ , $2$ , $1$ ,总和为 $\frac{(n - 1) n}{2}$ 。在引入 `flag` 优化后,最佳时间复杂度可达到 $O(n)$ 。

View File

@ -80,6 +80,12 @@
[class]{}-[func]{bucketSort}
```
=== "Rust"
```rust title="bucket_sort.rs"
[class]{}-[func]{bucket_sort}
```
!!! question "桶排序的适用场景是什么?"
桶排序适用于处理体量很大的数据。例如,输入数据包含 100 万个元素,由于空间限制,系统内存无法一次性加载所有数据。此时,可以将数据分成 1000 个桶,然后分别对每个桶进行排序,最后将结果合并。

View File

@ -78,6 +78,12 @@
[class]{}-[func]{countingSortNaive}
```
=== "Rust"
```rust title="counting_sort.rs"
[class]{}-[func]{counting_sort_naive}
```
!!! note "计数排序与桶排序的联系"
从桶排序的角度看,我们可以将计数排序中的计数数组 `counter` 的每个索引视为一个桶,将统计数量的过程看作是将各个元素分配到对应的桶中。本质上,计数排序是桶排序在整型数据下的一个特例。
@ -191,6 +197,12 @@ $$
[class]{}-[func]{countingSort}
```
=== "Rust"
```rust title="counting_sort.rs"
[class]{}-[func]{counting_sort}
```
## 算法特性
- **时间复杂度 $O(n + m)$** :涉及遍历 `nums` 和遍历 `counter` ,都使用线性时间。一般情况下 $n \gg m$ ,时间复杂度趋于 $O(n)$ 。

View File

@ -148,6 +148,14 @@
[class]{}-[func]{heapSort}
```
=== "Rust"
```rust title="heap_sort.rs"
[class]{}-[func]{sift_down}
[class]{}-[func]{heap_sort}
```
## 算法特性
- **时间复杂度 $O(n \log n)$ 、非自适应排序** :建堆操作使用 $O(n)$ 时间。从堆中提取最大元素的时间复杂度为 $O(\log n)$ ,共循环 $n - 1$ 轮。

View File

@ -85,6 +85,12 @@
[class]{}-[func]{insertionSort}
```
=== "Rust"
```rust title="insertion_sort.rs"
[class]{}-[func]{insertion_sort}
```
## 算法特性
- **时间复杂度 $O(n^2)$ 、自适应排序** :最差情况下,每次插入操作分别需要循环 $n - 1$ , $n-2$ , $\cdots$ , $2$ , $1$ 次,求和得到 $\frac{(n - 1) n}{2}$ ,因此时间复杂度为 $O(n^2)$ 。在遇到有序数据时,插入操作会提前终止。当输入数组完全有序时,插入排序达到最佳时间复杂度 $O(n)$ 。

View File

@ -139,6 +139,14 @@
[class]{}-[func]{mergeSort}
```
=== "Rust"
```rust title="merge_sort.rs"
[class]{}-[func]{merge}
[class]{}-[func]{merge_sort}
```
合并方法 `merge()` 代码中的难点包括:
- **在阅读代码时,需要特别注意各个变量的含义**。`nums` 的待合并区间为 `[left, right]` ,但由于 `tmp` 仅复制了 `nums` 该区间的元素,因此 `tmp` 对应区间为 `[0, right - left]` 。

View File

@ -125,6 +125,12 @@
[class]{QuickSort}-[func]{_partition}
```
=== "Rust"
```rust title="quick_sort.rs"
[class]{QuickSort}-[func]{partition}
```
## 算法流程
1. 首先,对原数组执行一次「哨兵划分」,得到未排序的左子数组和右子数组。
@ -199,6 +205,12 @@
[class]{QuickSort}-[func]{quickSort}
```
=== "Rust"
```rust title="quick_sort.rs"
[class]{QuickSort}-[func]{quick_sort}
```
## 算法特性
- **时间复杂度 $O(n \log n)$ 、自适应排序** :在平均情况下,哨兵划分的递归层数为 $\log n$ ,每层中的总循环数为 $n$ ,总体使用 $O(n \log n)$ 时间。在最差情况下,每轮哨兵划分操作都将长度为 $n$ 的数组划分为长度为 $0$ 和 $n - 1$ 的两个子数组,此时递归层数达到 $n$ 层,每层中的循环数为 $n$ ,总体使用 $O(n^2)$ 时间。
@ -311,6 +323,14 @@
[class]{QuickSortMedian}-[func]{_partition}
```
=== "Rust"
```rust title="quick_sort.rs"
[class]{QuickSortMedian}-[func]{median_three}
[class]{QuickSortMedian}-[func]{partition}
```
## 尾递归优化
**在某些输入下,快速排序可能占用空间较多**。以完全倒序的输入数组为例,由于每轮哨兵划分后右子数组长度为 $0$ ,递归树的高度会达到 $n - 1$ ,此时需要占用 $O(n)$ 大小的栈帧空间。
@ -382,3 +402,9 @@
```dart title="quick_sort.dart"
[class]{QuickSortTailCall}-[func]{quickSort}
```
=== "Rust"
```rust title="quick_sort.rs"
[class]{QuickSortTailCall}-[func]{quick_sort}
```

View File

@ -134,6 +134,16 @@ $$
[class]{}-[func]{radixSort}
```
=== "Rust"
```rust title="radix_sort.rs"
[class]{}-[func]{digit}
[class]{}-[func]{counting_sort_digit}
[class]{}-[func]{radix_sort}
```
!!! question "为什么从最低位开始排序?"
在连续的排序轮次中,后一轮排序会覆盖前一轮排序的结果。举例来说,如果第一轮排序结果 $a < b$ ,而第二轮排序结果 $a > b$ ,那么第二轮的结果将取代第一轮的结果。由于数字的高位优先级高于低位,我们应该先排序低位再排序高位。

View File

@ -111,6 +111,12 @@
[class]{}-[func]{selectionSort}
```
=== "Rust"
```rust title="selection_sort.rs"
[class]{}-[func]{selection_sort}
```
## 算法特性
- **时间复杂度为 $O(n^2)$ 、非自适应排序**:外循环共 $n - 1$ 轮,第一轮的未排序区间长度为 $n$ ,最后一轮的未排序区间长度为 $2$ ,即各轮外循环分别包含 $n$ , $n - 1$ , $\cdots$ , $2$ 轮内循环,求和为 $\frac{(n - 1)(n + 2)}{2}$ 。