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:
xBLACKICEx 2023-02-18 18:00:20 +01:00 committed by GitHub
parent 197a5f27fa
commit 53f45984f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 247 additions and 0 deletions

View file

@ -59,6 +59,21 @@ path = "chapter_searching/binary_search.rs"
name = "bubble_sort"
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
[[bin]]
name = "array_stack"

View 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);
}

View 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);
}

View 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);
}