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