forked from krahets/hello-algo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ feat(rust/sorting) add insertion, merge, quick sort code (krahets#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.
- Loading branch information
1 parent
197a5f2
commit 53f4598
Showing
4 changed files
with
247 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
/* | ||
* File: insertion_sort.rs | ||
* Created Time: 2023-02-13 | ||
* Author: xBLACKICEx ([email protected]) | ||
*/ | ||
|
||
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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
/** | ||
* File: merge_sort.rs | ||
* Created Time: 2023-02-14 | ||
* Author: xBLACKICEx ([email protected]) | ||
*/ | ||
|
||
/* 合并左子数组和右子数组 */ | ||
// 左子数组区间 [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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
/** | ||
* File: quick_sort.rs | ||
* Created Time: 2023-02-16 | ||
* Author: xBLACKICEx ([email protected]) | ||
*/ | ||
|
||
// 快速排序 | ||
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); | ||
} |