From 06917d3d833fc34f940de19378b96a209b724dd0 Mon Sep 17 00:00:00 2001 From: donjuanplatinum <donjuan@lecturify.net> Date: Wed, 12 Feb 2025 14:07:21 +0800 Subject: [PATCH] add inplace merge_sort no_std,utils rotate --- README.org | 6 +++ src/lib.rs | 4 +- src/sorting/merge_sort.rs | 73 +++++++++++++++++++++++---- src/sorting/mod.rs | 1 - src/tools.rs | 21 -------- src/utils.rs | 103 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 175 insertions(+), 33 deletions(-) delete mode 100644 src/tools.rs create mode 100644 src/utils.rs diff --git a/README.org b/README.org index db31991..8b4ad13 100644 --- a/README.org +++ b/README.org @@ -6,6 +6,9 @@ [[https://conventionalcommits.org][https://img.shields.io/badge/Conventional%20Commits-1.0.0-%23FE5196?logo=conventionalcommits&logoColor=white.svg]] ** Algorithms +- Features + - no_std + - std *** Sorting 排序 - [[./src/sorting/insertion_sort.rs::9][InsertionSort 插入排序]] - [[./src/sorting/selection_sort.rs::9][SelectionSort 选择排序]] @@ -27,3 +30,6 @@ - [[./src/math/pi.rs::6][pi 圆周率]] *** String 字符串 - [[./src/string/max_substring.rs::10][MaxSubarray 最大子数组]] + +*** utils 工具 +- [[./src/utils.rs::41][rotate 旋转数组]] diff --git a/src/lib.rs b/src/lib.rs index b389400..ed1edad 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,8 +18,8 @@ pub mod searching; /// Math pub mod math; -/// Tools -pub mod tools; +/// Utils +pub mod utils; /// String pub mod string; diff --git a/src/sorting/merge_sort.rs b/src/sorting/merge_sort.rs index c85ef9d..79f2277 100644 --- a/src/sorting/merge_sort.rs +++ b/src/sorting/merge_sort.rs @@ -1,4 +1,34 @@ -// ! maybe need fix +#[cfg(feature = "no_std")] +use crate::utils::rotate; + +#[cfg(feature = "no_std")] +fn merge<T>(array: &mut [T], mid: usize, comparator: fn(&T, &T) -> bool) { + let len = array.len(); + let mut left = 0; + let mut right = mid; + + while left < right && right < len { + if comparator(&array[left], &array[right]) { + left += 1; + } + // 此时comparator(array[left],array[right]) = false + else { + let tmp = right; + while right < len && comparator(&array[left], &array[right]) == false { + right += 1; + } + + // 此时comparator(array[left],array[right]) = true + // 在right到tmp之间的元素是需要与i到tmp旋转的 + let rotate_mid = tmp - left; + let slice = &mut array[left..right]; + rotate(slice, rotate_mid).unwrap(); + // 更新左指针位置 + left += right - tmp; + } + } +} + #[cfg(not(feature = "no_std"))] fn merge<T: Clone>(array: &mut [T], mid: usize, comparator: fn(&T, &T) -> bool) { let left = array[..mid].to_vec(); @@ -30,26 +60,51 @@ fn merge<T: Clone>(array: &mut [T], mid: usize, comparator: fn(&T, &T) -> bool) index += 1; } } + /// Merge Sort +/// - no_std启用时: 采用旋转元素与自底向上的归并排序 +/// - std启用时: 原始的归并排序 /// # Example /// ``` /// use algori::sorting::{merge_sort,is_sorted}; /// let mut a = [2,3,1,34,15,8,0,7,4,3,21,4,6,7,4,2341,321,41231,312,62]; /// merge_sort(&mut a ,|a,b| a<=b); -/// assert_eq!(is_sorted(&mut a ,|a,b| a<=b),true); +/// assert_eq!([0, 1, 2, 3, 3, 4, 4, 4, 6, 7, 7, 8, 15, 21, 34, 62, 312, 321, 2341, 41231],a) /// ``` +#[cfg(feature = "no_std")] +pub fn merge_sort<T>(array: &mut [T], comparator: fn(&T, &T) -> bool) { + let n = array.len(); + let mut size = 1; + + while size < n { + for left in (0..n).step_by(2 * size) { + let mid = left + size; + let right = core::cmp::min(left + 2 * size, n); + if mid < right { + merge(&mut array[left..right], mid - left, comparator); + } + } + size *= 2; + } +} + #[cfg(not(feature = "no_std"))] pub fn merge_sort<T: Clone>(array: &mut [T], comparator: fn(&T, &T) -> bool) { - if array.len() > 1 { - if array.len() > 1 { - let mid = array.len() / 2; - merge_sort(&mut array[..mid], comparator); - merge_sort(&mut array[mid..], comparator); - merge(array, mid, comparator); + let n = array.len(); + let mut size = 1; + + while size < n { + for left in (0..n).step_by(2 * size) { + let mid = left + size; + let right = core::cmp::min(left + 2 * size, n); + if mid < right { + merge(&mut array[left..right], mid - left, comparator); + } } + size *= 2; } } -#[cfg(not(feature = "no_std"))] + #[cfg(test)] mod tests { use super::super::is_sorted; diff --git a/src/sorting/mod.rs b/src/sorting/mod.rs index 2d929ec..27c9005 100644 --- a/src/sorting/mod.rs +++ b/src/sorting/mod.rs @@ -9,5 +9,4 @@ pub use self::insertion_sort::*; pub use self::selection_sort::*; pub use self::utils::*; -#[cfg(not(feature = "no_std"))] pub use self::merge_sort::*; diff --git a/src/tools.rs b/src/tools.rs deleted file mode 100644 index bea0cdd..0000000 --- a/src/tools.rs +++ /dev/null @@ -1,21 +0,0 @@ -/// test the time of function -/// # Examples -/// ``` -/// use algori::test_time; -/// use algori::sorting::insertion_sort; -/// let mut a = [1,4,6,7,2,2,1,4,65,6]; -/// test_time!("Insertion Sort",insertion_sort(&mut a,|a,b|a<=b)); -/// ``` -#[macro_export] -macro_rules! test_time { - ($title:literal,$func:expr) => { - let now = std::time::Instant::now(); - $func; - println!( - "Job:\t{}\nUsing\t{}\tseconds\n\t{}\tnanos", - $title, - now.elapsed().as_secs(), - now.elapsed().as_nanos() - ); - }; -} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..0361a7f --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,103 @@ +/// test the time of function +/// # Examples +/// ``` +/// use algori::test_time; +/// use algori::sorting::insertion_sort; +/// let mut a = [1,4,6,7,2,2,1,4,65,6]; +/// test_time!("Insertion Sort",insertion_sort(&mut a,|a,b|a<=b)); +/// ``` +#[macro_export] +macro_rules! test_time { + ($title:literal,$func:expr) => { + let now = std::time::Instant::now(); + $func; + println!( + "Job:\t{}\nUsing\t{}\tseconds\n\t{}\tnanos", + $title, + now.elapsed().as_secs(), + now.elapsed().as_nanos() + ); + }; +} + +fn reverse<T>(array: &mut [T], mut start: usize, mut end: usize) { + while start < end { + array.swap(start, end); + start += 1; + end -= 1; + } +} +/// 手摇旋转 +/// 旋转以 `mid` 为分界的切片 +/// - 若mid超出边界或者位于边界 那么返回Err(()) +/// - 若成功返回Ok(()) +/// # Example +/// ``` +/// use algori::utils::rotate; +/// let mut a = ['a','b','c','d','e','f']; +/// rotate(&mut a, 2); +/// assert_eq!(a,['c','d','e','f','a','b']); +/// ``` +pub fn rotate<T>(array: &mut [T], mid: usize) -> Result<(), ()> { + let len = array.len(); + // 越界Err + if mid >= len { + return Err(()); + } + if mid == 0 { + return Ok(()); + } + reverse(array, 0, mid - 1); + reverse(array, mid, len - 1); + reverse(array, 0, len - 1); + return Ok(()); +} + +#[cfg(test)] +mod rotate_test { + use crate::utils::rotate; + // 测试奇数的数组 + #[test] + fn odd() { + let mut a = ['a', 'b', 'c', 'd', 'e']; + rotate(&mut a, 2).unwrap(); + assert_eq!(a, ['c', 'd', 'e', 'a', 'b']); + } + // 偶数的数组 + #[test] + fn even() { + let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + rotate(&mut a, 2).unwrap(); + assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']); + } + // 下标越界 + #[test] + fn over_index() { + let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + let result = rotate(&mut a, 6); + assert_eq!(a, ['a', 'b', 'c', 'd', 'e', 'f']); + assert_eq!(result, Err(())); + } + // 相等 + #[test] + fn len() { + let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + let result = rotate(&mut a, 5); + assert_eq!(a, ['f', 'a', 'b', 'c', 'd', 'e']); + assert_eq!(result, Ok(())); + } + // 开始 + #[test] + fn start() { + let mut a = ['a', 'b', 'c', 'd', 'e', 'f']; + let result = rotate(&mut a, 0); + assert_eq!(a, ['a', 'b', 'c', 'd', 'e', 'f']); + assert_eq!(result, Ok(())); + } + #[test] + fn rotate_test1() { + let mut a = [20, 30, 40, 50, 15]; + rotate(&mut a, 4).unwrap(); + assert_eq!([15, 20, 30, 40, 50], a); + } +}