diff --git a/DIRECTORY.md b/DIRECTORY.md index 3685ba5bf56..1a690ef829d 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -298,6 +298,7 @@ * [Insertion Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/insertion_sort.rs) * [Intro Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/intro_sort.rs) * [Merge Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/merge_sort.rs) + * [Merge Sort Inplace](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/merge_sort_inplace.rs) * [Odd Even Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/odd_even_sort.rs) * [Pancake Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/pancake_sort.rs) * [Patience Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/patience_sort.rs) diff --git a/src/sorting/merge_sort_inplace.rs b/src/sorting/merge_sort_inplace.rs new file mode 100644 index 00000000000..abcdc2622dd --- /dev/null +++ b/src/sorting/merge_sort_inplace.rs @@ -0,0 +1,169 @@ +fn merge(array: &mut [T], mid: usize) { + let len = array.len(); + let mut left = 0; + let mut right = mid; + + while left < right && right < len { + if array[left] < array[right] { + left += 1; + } else { + let tmp = right; + while right < len && array[left] > array[right] { + right += 1; + } + let rotate_mid = tmp - left; + let slice = &mut array[left..right]; + slice.rotate_left(rotate_mid); + left += right - tmp; + } + } +} + +pub fn top_down_merge_sort_inplace(arr: &mut [T]) { + if arr.len() > 1 { + let mid = arr.len() / 2; + // Sort the left half recursively. + top_down_merge_sort_inplace(&mut arr[..mid]); + // Sort the right half recursively. + top_down_merge_sort_inplace(&mut arr[mid..]); + // Combine the two halves. + merge(arr, mid); + } +} + +pub fn bottom_up_merge_sort_inplace(a: &mut [T]) { + if a.len() > 1 { + let len: usize = a.len(); + let mut sub_array_size: usize = 1; + while sub_array_size < len { + let mut start_index: usize = 0; + // still have more than one sub-arrays to merge + while len - start_index > sub_array_size { + let end_idx: usize = if start_index + 2 * sub_array_size > len { + len + } else { + start_index + 2 * sub_array_size + }; + // merge a[start_index..start_index+sub_array_size] and a[start_index+sub_array_size..end_idx] + // NOTE: mid is a relative index number starting from `start_index` + merge(&mut a[start_index..end_idx], sub_array_size); + // update `start_index` to merge the next sub-arrays + start_index = end_idx; + } + sub_array_size *= 2; + } + } +} + +#[cfg(test)] +mod tests { + #[cfg(test)] + mod top_down_merge_sort { + use super::super::*; + use crate::sorting::have_same_elements; + use crate::sorting::is_sorted; + + #[test] + fn basic() { + let mut res = vec![10, 8, 4, 3, 1, 9, 2, 7, 5, 6]; + let cloned = res.clone(); + top_down_merge_sort_inplace(&mut res); + assert!(is_sorted(&res) && have_same_elements(&res, &cloned)); + } + + #[test] + fn basic_string() { + let mut res = vec!["a", "bb", "d", "cc"]; + let cloned = res.clone(); + top_down_merge_sort_inplace(&mut res); + assert!(is_sorted(&res) && have_same_elements(&res, &cloned)); + } + + #[test] + fn empty() { + let mut res = Vec::::new(); + let cloned = res.clone(); + top_down_merge_sort_inplace(&mut res); + assert!(is_sorted(&res) && have_same_elements(&res, &cloned)); + } + + #[test] + fn one_element() { + let mut res = vec![1]; + let cloned = res.clone(); + top_down_merge_sort_inplace(&mut res); + assert!(is_sorted(&res) && have_same_elements(&res, &cloned)); + } + + #[test] + fn pre_sorted() { + let mut res = vec![1, 2, 3, 4]; + let cloned = res.clone(); + top_down_merge_sort_inplace(&mut res); + assert!(is_sorted(&res) && have_same_elements(&res, &cloned)); + } + + #[test] + fn reverse_sorted() { + let mut res = vec![4, 3, 2, 1]; + let cloned = res.clone(); + top_down_merge_sort_inplace(&mut res); + assert!(is_sorted(&res) && have_same_elements(&res, &cloned)); + } + } + + #[cfg(test)] + mod bottom_up_merge_sort { + use super::super::*; + use crate::sorting::have_same_elements; + use crate::sorting::is_sorted; + + #[test] + fn basic() { + let mut res = vec![10, 8, 4, 3, 1, 9, 2, 7, 5, 6]; + let cloned = res.clone(); + bottom_up_merge_sort_inplace(&mut res); + assert!(is_sorted(&res) && have_same_elements(&res, &cloned)); + } + + #[test] + fn basic_string() { + let mut res = vec!["a", "bb", "d", "cc"]; + let cloned = res.clone(); + bottom_up_merge_sort_inplace(&mut res); + assert!(is_sorted(&res) && have_same_elements(&res, &cloned)); + } + + #[test] + fn empty() { + let mut res = Vec::::new(); + let cloned = res.clone(); + bottom_up_merge_sort_inplace(&mut res); + assert!(is_sorted(&res) && have_same_elements(&res, &cloned)); + } + + #[test] + fn one_element() { + let mut res = vec![1]; + let cloned = res.clone(); + bottom_up_merge_sort_inplace(&mut res); + assert!(is_sorted(&res) && have_same_elements(&res, &cloned)); + } + + #[test] + fn pre_sorted() { + let mut res = vec![1, 2, 3, 4]; + let cloned = res.clone(); + bottom_up_merge_sort_inplace(&mut res); + assert!(is_sorted(&res) && have_same_elements(&res, &cloned)); + } + + #[test] + fn reverse_sorted() { + let mut res = vec![4, 3, 2, 1]; + let cloned = res.clone(); + bottom_up_merge_sort_inplace(&mut res); + assert!(is_sorted(&res) && have_same_elements(&res, &cloned)); + } + } +} diff --git a/src/sorting/mod.rs b/src/sorting/mod.rs index 79be2b0b9e6..d4b2856484d 100644 --- a/src/sorting/mod.rs +++ b/src/sorting/mod.rs @@ -16,6 +16,7 @@ mod heap_sort; mod insertion_sort; mod intro_sort; mod merge_sort; +mod merge_sort_inplace; mod odd_even_sort; mod pancake_sort; mod patience_sort; @@ -54,6 +55,8 @@ pub use self::insertion_sort::insertion_sort; pub use self::intro_sort::intro_sort; pub use self::merge_sort::bottom_up_merge_sort; pub use self::merge_sort::top_down_merge_sort; +pub use self::merge_sort_inplace::bottom_up_merge_sort_inplace; +pub use self::merge_sort_inplace::top_down_merge_sort_inplace; pub use self::odd_even_sort::odd_even_sort; pub use self::pancake_sort::pancake_sort; pub use self::patience_sort::patience_sort; @@ -69,7 +72,6 @@ pub use self::tim_sort::tim_sort; pub use self::tree_sort::tree_sort; pub use self::wave_sort::wave_sort; pub use self::wiggle_sort::wiggle_sort; - #[cfg(test)] use std::cmp;