From 53f45984f9105c29bc2fcf7b119d3ccece513db2 Mon Sep 17 00:00:00 2001 From: xBLACKICEx Date: Sat, 18 Feb 2023 18:00:20 +0100 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat(rust/sorting)=20add=20insertio?= =?UTF-8?q?n,=20merge,=20quick=20sort=20code=20=20(#369)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ✨ 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. --- codes/rust/Cargo.toml | 15 ++ codes/rust/chapter_sorting/insertion_sort.rs | 29 ++++ codes/rust/chapter_sorting/merge_sort.rs | 57 ++++++++ codes/rust/chapter_sorting/quick_sort.rs | 146 +++++++++++++++++++ 4 files changed, 247 insertions(+) create mode 100644 codes/rust/chapter_sorting/insertion_sort.rs create mode 100644 codes/rust/chapter_sorting/merge_sort.rs create mode 100644 codes/rust/chapter_sorting/quick_sort.rs diff --git a/codes/rust/Cargo.toml b/codes/rust/Cargo.toml index 3d329b766..67d1b3d3e 100644 --- a/codes/rust/Cargo.toml +++ b/codes/rust/Cargo.toml @@ -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" diff --git a/codes/rust/chapter_sorting/insertion_sort.rs b/codes/rust/chapter_sorting/insertion_sort.rs new file mode 100644 index 000000000..af8bd2627 --- /dev/null +++ b/codes/rust/chapter_sorting/insertion_sort.rs @@ -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); +} \ No newline at end of file diff --git a/codes/rust/chapter_sorting/merge_sort.rs b/codes/rust/chapter_sorting/merge_sort.rs new file mode 100644 index 000000000..2ce0ebe40 --- /dev/null +++ b/codes/rust/chapter_sorting/merge_sort.rs @@ -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 = 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); +} \ No newline at end of file diff --git a/codes/rust/chapter_sorting/quick_sort.rs b/codes/rust/chapter_sorting/quick_sort.rs new file mode 100644 index 000000000..875329073 --- /dev/null +++ b/codes/rust/chapter_sorting/quick_sort.rs @@ -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); +} \ No newline at end of file