This commit is contained in:
krahets
2023-03-12 18:46:03 +08:00
parent 209d82a8cc
commit f6b9a75c8f
23 changed files with 406 additions and 359 deletions
+5 -5
View File
@@ -87,9 +87,9 @@ comments: true
=== "Python"
```python title="bubble_sort.py"
def bubble_sort(nums):
def bubble_sort(nums: List[int]) -> None:
""" 冒泡排序 """
n = len(nums)
n: int = len(nums)
# 外循环:待排序元素数量为 n-1, n-2, ..., 1
for i in range(n - 1, 0, -1):
# 内循环:冒泡操作
@@ -295,12 +295,12 @@ comments: true
=== "Python"
```python title="bubble_sort.py"
def bubble_sort_with_flag(nums):
def bubble_sort_with_flag(nums: List[int]) -> None:
""" 冒泡排序(标志优化) """
n = len(nums)
n: int = len(nums)
# 外循环:待排序元素数量为 n-1, n-2, ..., 1
for i in range(n - 1, 0, -1):
flag = False # 初始化标志位
flag: bool = False # 初始化标志位
# 内循环:冒泡操作
for j in range(i):
if nums[j] > nums[j + 1]:
+3 -3
View File
@@ -63,12 +63,12 @@ comments: true
=== "Python"
```python title="insertion_sort.py"
def insertion_sort(nums):
def insertion_sort(nums: List[int]) -> None:
""" 插入排序 """
# 外循环:base = nums[1], nums[2], ..., nums[n-1]
for i in range(1, len(nums)):
base = nums[i]
j = i - 1
base: int = nums[i]
j: int = i - 1
# 内循环:将 base 插入到左边的正确位置
while j >= 0 and nums[j] > base:
nums[j + 1] = nums[j] # 1. 将 nums[j] 向右移动一位
+68 -20
View File
@@ -146,18 +146,21 @@ comments: true
=== "Python"
```python title="merge_sort.py"
def merge(nums, left, mid, right):
def merge(nums: List[int], left: int, mid: int, right: int) -> None:
""" 合并左子数组和右子数组 """
# 左子数组区间 [left, mid]
# 右子数组区间 [mid + 1, right]
# 初始化辅助数组 借助 copy模块
tmp = nums[left:right + 1]
tmp: List[int] = nums[left:right + 1].copy()
# 左子数组的起始索引和结束索引
left_start, left_end = left - left, mid - left
left_start: int = 0
left_end: int = mid - left
# 右子数组的起始索引和结束索引
right_start, right_end = mid + 1 - left, right - left
right_start: int = mid + 1 - left
right_end: int = right - left
# i, j 分别指向左子数组、右子数组的首元素
i, j = left_start, right_start
i: int = left_start
j: int = right_start
# 通过覆盖原数组 nums 来合并左子数组和右子数组
for k in range(left, right + 1):
# 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
@@ -173,13 +176,13 @@ comments: true
nums[k] = tmp[j]
j += 1
def merge_sort(nums, left, right):
def merge_sort(nums: List[int], left: int, right: int) -> None:
""" 归并排序 """
# 终止条件
if left >= right:
return # 当子数组长度为 1 时终止递归
# 划分阶段
mid = (left + right) // 2 # 计算中点
mid: int = (left + right) // 2 # 计算中点
merge_sort(nums, left, mid) # 递归左子数组
merge_sort(nums, mid + 1, right) # 递归右子数组
# 合并阶段
@@ -189,11 +192,9 @@ comments: true
=== "Go"
```go title="merge_sort.go"
/*
合并左子数组和右子数组
子数组区间 [left, mid]
右子数组区间 [mid + 1, right]
*/
/* 合并左子数组和右子数组 */
// 左子数组区间 [left, mid]
// 右子数组区间 [mid + 1, right]
func merge(nums []int, left, mid, right int) {
// 初始化辅助数组 借助 copy 模块
tmp := make([]int, right-left+1)
@@ -224,6 +225,7 @@ comments: true
}
}
/* 归并排序 */
func mergeSort(nums []int, left, right int) {
// 终止条件
if left >= right {
@@ -267,7 +269,7 @@ comments: true
}
}
}
/* 归并排序 */
function mergeSort(nums, left, right) {
// 终止条件
@@ -301,10 +303,10 @@ comments: true
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
if (i > leftEnd) {
nums[k] = tmp[j++];
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
} else if (j > rightEnd || tmp[i] <= tmp[j]) {
nums[k] = tmp[i++];
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
} else {
nums[k] = tmp[j++];
}
@@ -378,11 +380,9 @@ comments: true
=== "Swift"
```swift title="merge_sort.swift"
/**
* 合并左子数组和右子数组
* 左子数组区间 [left, mid]
* 右子数组区间 [mid + 1, right]
*/
/* 合并左子数组和右子数组 */
// 左子数组区间 [left, mid]
// 右子数组区间 [mid + 1, right]
func merge(nums: inout [Int], left: Int, mid: Int, right: Int) {
// 初始化辅助数组
let tmp = Array(nums[left ..< (right + 1)])
@@ -433,7 +433,55 @@ comments: true
=== "Zig"
```zig title="merge_sort.zig"
// 合并左子数组和右子数组
// 左子数组区间 [left, mid]
// 右子数组区间 [mid + 1, right]
fn merge(nums: []i32, left: usize, mid: usize, right: usize) !void {
// 初始化辅助数组
var mem_arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer mem_arena.deinit();
const mem_allocator = mem_arena.allocator();
var tmp = try mem_allocator.alloc(i32, right + 1 - left);
std.mem.copy(i32, tmp, nums[left..right+1]);
// 左子数组的起始索引和结束索引
var leftStart = left - left;
var leftEnd = mid - left;
// 右子数组的起始索引和结束索引
var rightStart = mid + 1 - left;
var rightEnd = right - left;
// i, j 分别指向左子数组、右子数组的首元素
var i = leftStart;
var j = rightStart;
// 通过覆盖原数组 nums 来合并左子数组和右子数组
var k = left;
while (k <= right) : (k += 1) {
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
if (i > leftEnd) {
nums[k] = tmp[j];
j += 1;
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
} else if (j > rightEnd or tmp[i] <= tmp[j]) {
nums[k] = tmp[i];
i += 1;
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
} else {
nums[k] = tmp[j];
j += 1;
}
}
}
// 归并排序
fn mergeSort(nums: []i32, left: usize, right: usize) !void {
// 终止条件
if (left >= right) return; // 当子数组长度为 1 时终止递归
// 划分阶段
var mid = (left + right) / 2; // 计算中点
try mergeSort(nums, left, mid); // 递归左子数组
try mergeSort(nums, mid + 1, right); // 递归右子数组
// 合并阶段
try merge(nums, left, mid, right);
}
```
下面重点解释一下合并方法 `merge()` 的流程:
+8 -8
View File
@@ -100,7 +100,7 @@ comments: true
=== "Python"
```python title="quick_sort.py"
def partition(self, nums, left, right):
def partition(self, nums: List[int], left: int, right: int) -> int:
""" 哨兵划分 """
# 以 nums[left] 作为基准数
i, j = left, right
@@ -333,13 +333,13 @@ comments: true
=== "Python"
```python title="quick_sort.py"
def quick_sort(self, nums, left, right):
def quick_sort(self, nums: List[int], left: int, right: int) -> None:
""" 快速排序 """
# 子数组长度为 1 时终止递归
if left >= right:
return
# 哨兵划分
pivot = self.partition(nums, left, right)
pivot: int = self.partition(nums, left, right)
# 递归左子数组、右子数组
self.quick_sort(nums, left, pivot - 1)
self.quick_sort(nums, pivot + 1, right)
@@ -552,7 +552,7 @@ comments: true
=== "Python"
```python title="quick_sort.py"
def median_three(self, nums, left, mid, right):
def median_three(self, nums: List[int], left: int, mid: int, right: int) -> int:
""" 选取三个元素的中位数 """
# 此处使用异或运算来简化代码
# 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
@@ -562,10 +562,10 @@ comments: true
return mid
return right
def partition(self, nums, left, right):
def partition(self, nums: List[int], left: int, right: int) -> int:
""" 哨兵划分(三数取中值) """
# 以 nums[left] 作为基准数
med = self.median_three(nums, left, (left + right) // 2, right)
med: int = self.median_three(nums, left, (left + right) // 2, right)
# 将中位数交换至数组最左端
nums[left], nums[med] = nums[med], nums[left]
# 以 nums[left] 作为基准数
@@ -845,12 +845,12 @@ comments: true
=== "Python"
```python title="quick_sort.py"
def quick_sort(self, nums, left, right):
def quick_sort(self, nums: List[int], left: int, right: int) -> None:
""" 快速排序(尾递归优化) """
# 子数组长度为 1 时终止
while left < right:
# 哨兵划分操作
pivot = self.partition(nums, left, right)
pivot: int = self.partition(nums, left, right)
# 对两个子数组中较短的那个执行快排
if pivot - left < right - pivot:
self.quick_sort(nums, left, pivot - 1) # 递归排序左子数组