diff --git a/DIRECTORY.md b/DIRECTORY.md index 1dd188f69a8..2a1c44af6f1 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -301,6 +301,7 @@ * [Selection Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/selection_sort.rs) * [Shell Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/shell_sort.rs) * [Sleep Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/sleep_sort.rs) + * [Smooth Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/smooth_sort.rs) * [Sort Utils](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/sort_utils.rs) * [Stooge Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/stooge_sort.rs) * [Tim Sort](https://github.com/TheAlgorithms/Rust/blob/master/src/sorting/tim_sort.rs) diff --git a/src/sorting/mod.rs b/src/sorting/mod.rs index 11486f36ab9..b0c3ad12bb5 100644 --- a/src/sorting/mod.rs +++ b/src/sorting/mod.rs @@ -26,6 +26,7 @@ mod radix_sort; mod selection_sort; mod shell_sort; mod sleep_sort; +mod smooth_sort; #[cfg(test)] mod sort_utils; mod stooge_sort; @@ -64,6 +65,7 @@ pub use self::radix_sort::radix_sort; pub use self::selection_sort::selection_sort; pub use self::shell_sort::shell_sort; pub use self::sleep_sort::sleep_sort; +pub use self::smooth_sort::smooth_sort; pub use self::stooge_sort::stooge_sort; pub use self::tim_sort::tim_sort; pub use self::tree_sort::tree_sort; diff --git a/src/sorting/smooth_sort.rs b/src/sorting/smooth_sort.rs new file mode 100644 index 00000000000..2b15c3d2e43 --- /dev/null +++ b/src/sorting/smooth_sort.rs @@ -0,0 +1,102 @@ +pub fn smooth_sort(nums: &mut [i32]) { + let n = nums.len(); + if n <= 1 { + return; + } + + let mut sizes = vec![0; n]; + let mut heaps = 0; + + for i in 0..n { + add_to_leonardo_heap(nums, i, &mut sizes, &mut heaps); + } + + for i in (0..n).rev() { + remove_from_leonardo_heap(nums, i, &mut sizes, &mut heaps); + } +} + +fn add_to_leonardo_heap(nums: &mut [i32], index: usize, sizes: &mut Vec, heaps: &mut usize) { + if *heaps >= 2 && sizes[*heaps - 2] == sizes[*heaps - 1] + 1 { + sizes[*heaps - 2] += 1; + sizes.pop(); + *heaps -= 1; + } else if *heaps >= 2 && sizes[*heaps - 1] == sizes[*heaps - 2] + 1 { + sizes[*heaps - 1] += 1; + } else { + sizes.push(1); + } + heapify_leonardo(nums, index, sizes, *heaps); +} + +fn remove_from_leonardo_heap(nums: &mut [i32], index: usize, sizes: &mut Vec, heaps: &mut usize) { + let size = sizes.pop().unwrap_or(0); + *heaps -= 1; + if size >= 2 { + sizes.push(size - 1); + sizes.push(size - 2); + *heaps += 2; + heapify_leonardo(nums, index - size + 1, sizes, *heaps - 2); + heapify_leonardo(nums, index - 1, sizes, *heaps - 1); + } +} + +fn heapify_leonardo(nums: &mut [i32], index: usize, sizes: &Vec, mut heaps: usize) { + let mut current = index; + let mut heap_size = sizes[heaps]; + + while heaps > 1 { + if heap_size > current { + break; + } + + let left_child = current.saturating_sub(heap_size); + let right_child = current.saturating_sub(1); + + if nums[current] < nums[left_child] { + nums.swap(current, left_child); + current = left_child; + } else if nums[current] < nums[right_child] { + nums.swap(current, right_child); + current = right_child; + } else { + break; + } + + heaps -= 1; + heap_size -= 1; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn smooth_sort_example_1() { + let mut arr = vec![3, 5, 2, 1, 6, 4]; + smooth_sort(&mut arr); + assert_eq!(arr, vec![1, 2, 3, 4, 5, 6]); + } + + #[test] + fn smooth_sort_example_2() { + let mut arr = vec![4, 1, 3, 5, 2]; + smooth_sort(&mut arr); + assert_eq!(arr, vec![1, 2, 3, 4, 5]); + } + + #[test] + fn smooth_sort_repeated_elements() { + let mut arr = vec![5, 5, 5, 5]; + smooth_sort(&mut arr); + assert_eq!(arr, vec![5, 5, 5, 5]); + } + + #[test] + fn smooth_sort_large_elements() { + let mut arr = vec![100, 200, 5, 10, 15]; + smooth_sort(&mut arr); + assert_eq!(arr, vec![5, 10, 15, 100, 200]); + } +}