This commit is contained in:
krahets
2023-10-08 01:43:28 +08:00
parent 3d2d669b43
commit baac2d11a7
52 changed files with 999 additions and 625 deletions

View File

@@ -102,16 +102,14 @@ comments: true
```csharp title="bubble_sort.cs"
/* 冒泡排序 */
void bubbleSort(int[] nums) {
void BubbleSort(int[] nums) {
// 外循环:未排序区间为 [0, i]
for (int i = nums.Length - 1; i > 0; i--) {
// 内循环:将未排序区间 [0, i] 中的最大元素交换至该区间的最右端
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
int tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
(nums[j + 1], nums[j]) = (nums[j], nums[j + 1]);
}
}
}
@@ -353,7 +351,7 @@ comments: true
```csharp title="bubble_sort.cs"
/* 冒泡排序(标志优化)*/
void bubbleSortWithFlag(int[] nums) {
void BubbleSortWithFlag(int[] nums) {
// 外循环:未排序区间为 [0, i]
for (int i = nums.Length - 1; i > 0; i--) {
bool flag = false; // 初始化标志位
@@ -361,9 +359,7 @@ comments: true
for (int j = 0; j < i; j++) {
if (nums[j] > nums[j + 1]) {
// 交换 nums[j] 与 nums[j + 1]
int tmp = nums[j];
nums[j] = nums[j + 1];
nums[j + 1] = tmp;
(nums[j + 1], nums[j]) = (nums[j], nums[j + 1]);
flag = true; // 记录交换元素
}
}

View File

@@ -113,10 +113,10 @@ comments: true
```csharp title="bucket_sort.cs"
/* 桶排序 */
void bucketSort(float[] nums) {
void BucketSort(float[] nums) {
// 初始化 k = n/2 个桶,预期向每个桶分配 2 个元素
int k = nums.Length / 2;
List<List<float>> buckets = new List<List<float>>();
List<List<float>> buckets = new();
for (int i = 0; i < k; i++) {
buckets.Add(new List<float>());
}

View File

@@ -100,7 +100,7 @@ comments: true
```csharp title="counting_sort.cs"
/* 计数排序 */
// 简单实现,无法用于排序对象
void countingSortNaive(int[] nums) {
void CountingSortNaive(int[] nums) {
// 1. 统计数组最大元素 m
int m = 0;
foreach (int num in nums) {
@@ -475,7 +475,7 @@ $$
```csharp title="counting_sort.cs"
/* 计数排序 */
// 完整实现,可排序对象,并且是稳定排序
void countingSort(int[] nums) {
void CountingSort(int[] nums) {
// 1. 统计数组最大元素 m
int m = 0;
foreach (int num in nums) {

View File

@@ -192,7 +192,7 @@ comments: true
```csharp title="heap_sort.cs"
/* 堆的长度为 n ,从节点 i 开始,从顶至底堆化 */
void siftDown(int[] nums, int n, int i) {
void SiftDown(int[] nums, int n, int i) {
while (true) {
// 判断节点 i, l, r 中值最大的节点,记为 ma
int l = 2 * i + 1;
@@ -213,17 +213,17 @@ comments: true
}
/* 堆排序 */
void heapSort(int[] nums) {
void HeapSort(int[] nums) {
// 建堆操作:堆化除叶节点以外的其他所有节点
for (int i = nums.Length / 2 - 1; i >= 0; i--) {
siftDown(nums, nums.Length, i);
SiftDown(nums, nums.Length, i);
}
// 从堆中提取最大元素,循环 n-1 轮
for (int i = nums.Length - 1; i > 0; i--) {
// 交换根节点与最右叶节点(即交换首元素与尾元素)
(nums[i], nums[0]) = (nums[0], nums[i]);
// 以根节点为起点,从顶至底进行堆化
siftDown(nums, i, 0);
SiftDown(nums, i, 0);
}
}
```

View File

@@ -83,7 +83,7 @@ comments: true
```csharp title="insertion_sort.cs"
/* 插入排序 */
void insertionSort(int[] nums) {
void InsertionSort(int[] nums) {
// 外循环:已排序元素数量为 1, 2, ..., n
for (int i = 1; i < nums.Length; i++) {
int bas = nums[i], j = i - 1;

View File

@@ -197,7 +197,7 @@ comments: true
/* 合并左子数组和右子数组 */
// 左子数组区间 [left, mid]
// 右子数组区间 [mid + 1, right]
void merge(int[] nums, int left, int mid, int right) {
void Merge(int[] nums, int left, int mid, int right) {
// 初始化辅助数组
int[] tmp = nums[left..(right + 1)];
// 左子数组的起始索引和结束索引
@@ -221,15 +221,15 @@ comments: true
}
/* 归并排序 */
void mergeSort(int[] nums, int left, int right) {
void MergeSort(int[] nums, int left, int right) {
// 终止条件
if (left >= right) return; // 当子数组长度为 1 时终止递归
// 划分阶段
int mid = (left + right) / 2; // 计算中点
mergeSort(nums, left, mid); // 递归左子数组
mergeSort(nums, mid + 1, right); // 递归右子数组
MergeSort(nums, left, mid); // 递归左子数组
MergeSort(nums, mid + 1, right); // 递归右子数组
// 合并阶段
merge(nums, left, mid, right);
Merge(nums, left, mid, right);
}
```

View File

@@ -122,14 +122,12 @@ comments: true
```csharp title="quick_sort.cs"
/* 元素交换 */
void swap(int[] nums, int i, int j) {
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
void Swap(int[] nums, int i, int j) {
(nums[j], nums[i]) = (nums[i], nums[j]);
}
/* 哨兵划分 */
int partition(int[] nums, int left, int right) {
int Partition(int[] nums, int left, int right) {
// 以 nums[left] 作为基准数
int i = left, j = right;
while (i < j) {
@@ -137,9 +135,9 @@ comments: true
j--; // 从右向左找首个小于基准数的元素
while (i < j && nums[i] <= nums[left])
i++; // 从左向右找首个大于基准数的元素
swap(nums, i, j); // 交换这两个元素
Swap(nums, i, j); // 交换这两个元素
}
swap(nums, i, left); // 将基准数交换至两子数组的分界线
Swap(nums, i, left); // 将基准数交换至两子数组的分界线
return i; // 返回基准数的索引
}
```
@@ -423,15 +421,15 @@ comments: true
```csharp title="quick_sort.cs"
/* 快速排序 */
void quickSort(int[] nums, int left, int right) {
void QuickSort(int[] nums, int left, int right) {
// 子数组长度为 1 时终止递归
if (left >= right)
return;
// 哨兵划分
int pivot = partition(nums, left, right);
int pivot = Partition(nums, left, right);
// 递归左子数组、右子数组
quickSort(nums, left, pivot - 1);
quickSort(nums, pivot + 1, right);
QuickSort(nums, left, pivot - 1);
QuickSort(nums, pivot + 1, right);
}
```
@@ -719,7 +717,7 @@ comments: true
```csharp title="quick_sort.cs"
/* 选取三个元素的中位数 */
int medianThree(int[] nums, int left, int mid, int right) {
int MedianThree(int[] nums, int left, int mid, int right) {
// 此处使用异或运算来简化代码
// 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
if ((nums[left] < nums[mid]) ^ (nums[left] < nums[right]))
@@ -731,11 +729,11 @@ comments: true
}
/* 哨兵划分(三数取中值) */
int partition(int[] nums, int left, int right) {
int Partition(int[] nums, int left, int right) {
// 选取三个候选元素的中位数
int med = medianThree(nums, left, (left + right) / 2, right);
int med = MedianThree(nums, left, (left + right) / 2, right);
// 将中位数交换至数组最左端
swap(nums, left, med);
Swap(nums, left, med);
// 以 nums[left] 作为基准数
int i = left, j = right;
while (i < j) {
@@ -743,9 +741,9 @@ comments: true
j--; // 从右向左找首个小于基准数的元素
while (i < j && nums[i] <= nums[left])
i++; // 从左向右找首个大于基准数的元素
swap(nums, i, j); // 交换这两个元素
Swap(nums, i, j); // 交换这两个元素
}
swap(nums, i, left); // 将基准数交换至两子数组的分界线
Swap(nums, i, left); // 将基准数交换至两子数组的分界线
return i; // 返回基准数的索引
}
```
@@ -1125,17 +1123,17 @@ comments: true
```csharp title="quick_sort.cs"
/* 快速排序(尾递归优化) */
void quickSort(int[] nums, int left, int right) {
void QuickSort(int[] nums, int left, int right) {
// 子数组长度为 1 时终止
while (left < right) {
// 哨兵划分操作
int pivot = partition(nums, left, right);
int pivot = Partition(nums, left, right);
// 对两个子数组中较短的那个执行快排
if (pivot - left < right - pivot) {
quickSort(nums, left, pivot - 1); // 递归排序左子数组
QuickSort(nums, left, pivot - 1); // 递归排序左子数组
left = pivot + 1; // 剩余未排序区间为 [pivot + 1, right]
} else {
quickSort(nums, pivot + 1, right); // 递归排序右子数组
QuickSort(nums, pivot + 1, right); // 递归排序右子数组
right = pivot - 1; // 剩余未排序区间为 [left, pivot - 1]
}
}

View File

@@ -183,19 +183,19 @@ $$
```csharp title="radix_sort.cs"
/* 获取元素 num 的第 k 位,其中 exp = 10^(k-1) */
int digit(int num, int exp) {
int Digit(int num, int exp) {
// 传入 exp 而非 k 可以避免在此重复执行昂贵的次方计算
return (num / exp) % 10;
}
/* 计数排序(根据 nums 第 k 位排序) */
void countingSortDigit(int[] nums, int exp) {
void CountingSortDigit(int[] nums, int exp) {
// 十进制的位范围为 0~9 ,因此需要长度为 10 的桶
int[] counter = new int[10];
int n = nums.Length;
// 统计 0~9 各数字的出现次数
for (int i = 0; i < n; i++) {
int d = digit(nums[i], exp); // 获取 nums[i] 第 k 位,记为 d
int d = Digit(nums[i], exp); // 获取 nums[i] 第 k 位,记为 d
counter[d]++; // 统计数字 d 的出现次数
}
// 求前缀和,将“出现个数”转换为“数组索引”
@@ -205,7 +205,7 @@ $$
// 倒序遍历,根据桶内统计结果,将各元素填入 res
int[] res = new int[n];
for (int i = n - 1; i >= 0; i--) {
int d = digit(nums[i], exp);
int d = Digit(nums[i], exp);
int j = counter[d] - 1; // 获取 d 在数组中的索引 j
res[j] = nums[i]; // 将当前元素填入索引 j
counter[d]--; // 将 d 的数量减 1
@@ -217,7 +217,7 @@ $$
}
/* 基数排序 */
void radixSort(int[] nums) {
void RadixSort(int[] nums) {
// 获取数组的最大元素,用于判断最大位数
int m = int.MinValue;
foreach (int num in nums) {
@@ -229,7 +229,7 @@ $$
// k = 1 -> exp = 1
// k = 2 -> exp = 10
// 即 exp = 10^(k-1)
countingSortDigit(nums, exp);
CountingSortDigit(nums, exp);
}
}
```

View File

@@ -114,7 +114,7 @@ comments: true
```csharp title="selection_sort.cs"
/* 选择排序 */
void selectionSort(int[] nums) {
void SelectionSort(int[] nums) {
int n = nums.Length;
// 外循环:未排序区间为 [i, n-1]
for (int i = 0; i < n - 1; i++) {