mirror of
https://github.com/krahets/hello-algo.git
synced 2024-12-26 02:56:29 +08:00
✨ feat(rust/sorting) add insertion, merge, quick sort code (#369)
* ✨ feat(rust/sorting): add insertion_sort * ✨ feat(rust/sorting): add merge sort * ✨ feat(rust/sorting): add quick sort * 📃 docs(rust/sorting): add & correct some missing comments. * 📃 docs(rust/sorting): add & correct some missing comments.
This commit is contained in:
parent
197a5f27fa
commit
53f45984f9
4 changed files with 247 additions and 0 deletions
|
@ -59,6 +59,21 @@ path = "chapter_searching/binary_search.rs"
|
||||||
name = "bubble_sort"
|
name = "bubble_sort"
|
||||||
path = "chapter_sorting/bubble_sort.rs"
|
path = "chapter_sorting/bubble_sort.rs"
|
||||||
|
|
||||||
|
# Run Command: cargo run --bin insertion_sort
|
||||||
|
[[bin]]
|
||||||
|
name = "insertion_sort"
|
||||||
|
path = "chapter_sorting/insertion_sort.rs"
|
||||||
|
|
||||||
|
# Run Command: cargo run --bin quick_sort
|
||||||
|
[[bin]]
|
||||||
|
name = "quick_sort"
|
||||||
|
path = "chapter_sorting/quick_sort.rs"
|
||||||
|
|
||||||
|
# Run Command: cargo run --bin merge_sort
|
||||||
|
[[bin]]
|
||||||
|
name = "merge_sort"
|
||||||
|
path = "chapter_sorting/merge_sort.rs"
|
||||||
|
|
||||||
# Run Command: cargo run --bin array_stack
|
# Run Command: cargo run --bin array_stack
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "array_stack"
|
name = "array_stack"
|
||||||
|
|
29
codes/rust/chapter_sorting/insertion_sort.rs
Normal file
29
codes/rust/chapter_sorting/insertion_sort.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* File: insertion_sort.rs
|
||||||
|
* Created Time: 2023-02-13
|
||||||
|
* Author: xBLACKICEx (xBLACKICEx@outlook.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
include!("../include/include.rs");
|
||||||
|
|
||||||
|
/*插入排序 */
|
||||||
|
fn insertion_sort(nums: &mut [i32]) {
|
||||||
|
// 外循环:base = nums[1], nums[2], ..., nums[n-1]
|
||||||
|
for i in 1..nums.len() {
|
||||||
|
let (base, mut j) = (nums[i], (i - 1) as i32);
|
||||||
|
// 内循环:将 base 插入到左边的正确位置
|
||||||
|
while j >= 0 && nums[j as usize] > base {
|
||||||
|
nums[(j + 1) as usize] = nums[j as usize]; // 1. 将 nums[j] 向右移动一位
|
||||||
|
j -= 1;
|
||||||
|
}
|
||||||
|
nums[(j + 1) as usize] = base; // 2. 将 base 赋值到正确位置
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Driver Code */
|
||||||
|
fn main() {
|
||||||
|
let mut nums = [4, 1, 3, 1, 5, 2];
|
||||||
|
insertion_sort(&mut nums);
|
||||||
|
print!("插入排序完成后 nums = ");
|
||||||
|
print_util::print_array(&nums);
|
||||||
|
}
|
57
codes/rust/chapter_sorting/merge_sort.rs
Normal file
57
codes/rust/chapter_sorting/merge_sort.rs
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
/**
|
||||||
|
* File: merge_sort.rs
|
||||||
|
* Created Time: 2023-02-14
|
||||||
|
* Author: xBLACKICEx (xBLACKICEx@outlook.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 合并左子数组和右子数组 */
|
||||||
|
// 左子数组区间 [left, mid]
|
||||||
|
// 右子数组区间 [mid + 1, right]
|
||||||
|
fn merge(nums: &mut [i32], left: usize, mid: usize, right: usize) {
|
||||||
|
// 初始化辅助数组
|
||||||
|
let tmp: Vec<i32> = nums[left..right + 1].to_vec();
|
||||||
|
// 左子数组的起始索引和结束索引
|
||||||
|
let (left_start, left_end) = (left - left, mid - left);
|
||||||
|
// 右子数组的起始索引和结束索引
|
||||||
|
let (right_start, right_end) = (mid + 1 - left, right-left);
|
||||||
|
// i, j 分别指向左子数组、右子数组的首元素
|
||||||
|
let (mut l_corrent, mut r_corrent) = (left_start, right_start);
|
||||||
|
// 通过覆盖原数组 nums 来合并左子数组和右子数组
|
||||||
|
for k in left..right + 1 {
|
||||||
|
// 若“左子数组已全部合并完”,则选取右子数组元素,并且 j++
|
||||||
|
if l_corrent > left_end {
|
||||||
|
nums[k] = tmp[r_corrent];
|
||||||
|
r_corrent += 1;
|
||||||
|
}
|
||||||
|
// 否则,若“右子数组已全部合并完”或“左子数组元素 <= 右子数组元素”,则选取左子数组元素,并且 i++
|
||||||
|
else if r_corrent > right_end || tmp[l_corrent] <= tmp[r_corrent] {
|
||||||
|
nums[k] = tmp[l_corrent];
|
||||||
|
l_corrent += 1;
|
||||||
|
}
|
||||||
|
// 否则,若“左右子数组都未全部合并完”且“左子数组元素 > 右子数组元素”,则选取右子数组元素,并且 j++
|
||||||
|
else {
|
||||||
|
nums[k] = tmp[r_corrent];
|
||||||
|
r_corrent += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 归并排序 */
|
||||||
|
fn merge_sort(left: usize, right: usize, nums: &mut [i32]) {
|
||||||
|
// 终止条件
|
||||||
|
if left >= right { return; } // 当子数组长度为 1 时终止递归
|
||||||
|
// 划分阶段
|
||||||
|
let mid = (left + right) / 2; // 计算中点
|
||||||
|
merge_sort(left, mid, nums); // 递归左子数组
|
||||||
|
merge_sort(mid + 1, right, nums); // 递归右子数组
|
||||||
|
// 合并阶段
|
||||||
|
merge(nums, left, mid, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Driver Code */
|
||||||
|
fn main() {
|
||||||
|
/* 归并排序 */
|
||||||
|
let mut nums = [7, 3, 2, 6, 0, 1, 5, 4];
|
||||||
|
merge_sort(0, nums.len() - 1, &mut nums);
|
||||||
|
println!("归并排序完成后 nums = {:?}", nums);
|
||||||
|
}
|
146
codes/rust/chapter_sorting/quick_sort.rs
Normal file
146
codes/rust/chapter_sorting/quick_sort.rs
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
/**
|
||||||
|
* File: quick_sort.rs
|
||||||
|
* Created Time: 2023-02-16
|
||||||
|
* Author: xBLACKICEx (xBLACKICE@outlook.com)
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 快速排序
|
||||||
|
struct QuickSort;
|
||||||
|
// 快速排序(中位基准数优化)
|
||||||
|
struct QuickSortMedian;
|
||||||
|
// 快速排序(尾递归优化)
|
||||||
|
struct QuickSortTailCall;
|
||||||
|
|
||||||
|
/* 快速排序 */
|
||||||
|
impl QuickSort {
|
||||||
|
/* 哨兵划分 */
|
||||||
|
fn partition(nums: &mut [i32], left: usize, right: usize) -> usize {
|
||||||
|
// 以 nums[left] 作为基准数
|
||||||
|
let (mut i, mut j) = (left, right);
|
||||||
|
while i < j {
|
||||||
|
while i < j && nums[j] >= nums[left] {
|
||||||
|
j -= 1; // 从右向左找首个小于基准数的元素
|
||||||
|
}
|
||||||
|
while i < j && nums[i] <= nums[left] {
|
||||||
|
i += 1; // 从左向右找首个大于基准数的元素
|
||||||
|
}
|
||||||
|
nums.swap(i, j); // 交换这两个元素
|
||||||
|
}
|
||||||
|
nums.swap(i, left); // 将基准数交换至两子数组的分界线
|
||||||
|
i // 返回基准数的索引
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn quick_sort(left: i32, right: i32, nums: &mut [i32]) {
|
||||||
|
// 子数组长度为 1 时终止递归
|
||||||
|
if left >= right {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 哨兵划分
|
||||||
|
let pivot = Self::partition(nums, left as usize, right as usize) as i32;
|
||||||
|
// 递归左子数组、右子数组
|
||||||
|
Self::quick_sort(left, pivot - 1, nums);
|
||||||
|
Self::quick_sort(pivot + 1, right, nums);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 快速排序(中位基准数优化) */
|
||||||
|
impl QuickSortMedian {
|
||||||
|
/* 选取三个元素的中位数 */
|
||||||
|
fn median_three(nums: &mut [i32], left: usize, mid: usize, right: usize) -> usize {
|
||||||
|
// 使用了异或操作来简化代码
|
||||||
|
// 异或规则为 0 ^ 0 = 1 ^ 1 = 0, 0 ^ 1 = 1 ^ 0 = 1
|
||||||
|
if (nums[left] < nums[mid]) ^ (nums[left] < nums[right]) {
|
||||||
|
return left;
|
||||||
|
} else if (nums[mid] < nums[left]) ^ (nums[mid] < nums[right]) {
|
||||||
|
return mid;
|
||||||
|
}
|
||||||
|
right
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 哨兵划分(三数取中值) */
|
||||||
|
fn partition(nums: &mut [i32], left: usize, right: usize) -> usize {
|
||||||
|
// 选取三个候选元素的中位数
|
||||||
|
let med = Self::median_three(nums, left, (left + right) / 2, right);
|
||||||
|
// 将中位数交换至数组最左端
|
||||||
|
nums.swap(left, med);
|
||||||
|
// 以 nums[left] 作为基准数
|
||||||
|
let (mut i, mut j) = (left, right);
|
||||||
|
while i < j {
|
||||||
|
while i < j && nums[j] >= nums[left] {
|
||||||
|
j -= 1; // 从右向左找首个小于基准数的元素
|
||||||
|
}
|
||||||
|
while i < j && nums[i] <= nums[left] {
|
||||||
|
i += 1; // 从左向右找首个大于基准数的元素
|
||||||
|
}
|
||||||
|
nums.swap(i, j); // 交换这两个元素
|
||||||
|
}
|
||||||
|
nums.swap(i, left); // 将基准数交换至两子数组的分界线
|
||||||
|
i // 返回基准数的索引
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn quick_sort(left: i32, right: i32, nums: &mut [i32]) {
|
||||||
|
// 子数组长度为 1 时终止递归
|
||||||
|
if left >= right {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 哨兵划分
|
||||||
|
let pivot = Self::partition(nums, left as usize, right as usize) as i32;
|
||||||
|
// 递归左子数组、右子数组
|
||||||
|
Self::quick_sort(left, pivot - 1, nums);
|
||||||
|
Self::quick_sort(pivot + 1, right, nums);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 快速排序(尾递归优化) */
|
||||||
|
impl QuickSortTailCall {
|
||||||
|
/* 哨兵划分 */
|
||||||
|
fn partition(nums: &mut [i32], left: usize, right: usize) -> usize {
|
||||||
|
// 以 nums[left] 作为基准数
|
||||||
|
let (mut i, mut j) = (left, right);
|
||||||
|
|
||||||
|
while i < j {
|
||||||
|
while i < j && nums[j] >= nums[left] {
|
||||||
|
j -= 1; // 从右向左找首个小于基准数的元素
|
||||||
|
}
|
||||||
|
while i < j && nums[i] <= nums[left] {
|
||||||
|
i += 1; // 从左向右找首个大于基准数的元素
|
||||||
|
}
|
||||||
|
nums.swap(i, j); // 交换这两个元素
|
||||||
|
}
|
||||||
|
nums.swap(i, left); // 将基准数交换至两子数组的分界线
|
||||||
|
i // 返回基准数的索引
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn quick_sort(mut left: i32, mut right: i32, nums: &mut [i32]) {
|
||||||
|
// 子数组长度为 1 时终止
|
||||||
|
while left < right {
|
||||||
|
// 哨兵划分操作
|
||||||
|
let pivot = Self::partition(nums, left as usize, right as usize) as i32;
|
||||||
|
// 对两个子数组中较短的那个执行快排
|
||||||
|
if pivot - left < right - pivot {
|
||||||
|
Self::quick_sort(left, pivot - 1, nums); // 递归排序左子数组
|
||||||
|
left = pivot + 1; // 剩余待排序区间为 [pivot + 1, right]
|
||||||
|
} else {
|
||||||
|
Self::quick_sort(pivot + 1, right, nums); // 递归排序右子数组
|
||||||
|
right = pivot - 1; // 剩余待排序区间为 [left, pivot - 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
/* 快速排序 */
|
||||||
|
let mut nums = [2, 4, 1, 0, 3, 5];
|
||||||
|
QuickSort::quick_sort(0, (nums.len() - 1) as i32, &mut nums);
|
||||||
|
println!("快速排序完成后 nums = {:?}", nums);
|
||||||
|
|
||||||
|
/* 快速排序(中位基准数优化) */
|
||||||
|
let mut nums = [2, 4, 1, 0, 3, 5];
|
||||||
|
QuickSortMedian::quick_sort(0, (nums.len() - 1) as i32, &mut nums);
|
||||||
|
println!("快速排序(中位基准数优化)完成后 nums = {:?}", nums);
|
||||||
|
|
||||||
|
/* 快速排序(尾递归优化) */
|
||||||
|
let mut nums = [2, 4, 1, 0, 3, 5];
|
||||||
|
QuickSortTailCall::quick_sort(0, (nums.len() - 1) as i32, &mut nums);
|
||||||
|
println!("快速排序(尾递归优化)完成后 nums = {:?}", nums);
|
||||||
|
}
|
Loading…
Reference in a new issue