Skip to content

Commit c43d98c

Browse files
add inplace merge sort
1 parent ae10da6 commit c43d98c

File tree

2 files changed

+172
-1
lines changed

2 files changed

+172
-1
lines changed

src/sorting/merge_sort_inplace.rs

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
fn merge<T: Ord>(array: &mut [T], mid: usize) {
2+
let len = array.len();
3+
let mut left = 0;
4+
let mut right = mid;
5+
6+
while left < right && right < len {
7+
if &array[left] < &array[right] {
8+
left += 1;
9+
} else {
10+
let tmp = right;
11+
while right < len && &array[left] > &array[right] {
12+
right += 1;
13+
}
14+
let rotate_mid = tmp - left;
15+
let slice = &mut array[left..right];
16+
slice.rotate_left(rotate_mid);
17+
left += right - tmp;
18+
}
19+
}
20+
}
21+
22+
pub fn top_down_merge_sort_inplace<T: Ord>(arr: &mut [T]) {
23+
if arr.len() > 1 {
24+
let mid = arr.len() / 2;
25+
// Sort the left half recursively.
26+
top_down_merge_sort_inplace(&mut arr[..mid]);
27+
// Sort the right half recursively.
28+
top_down_merge_sort_inplace(&mut arr[mid..]);
29+
// Combine the two halves.
30+
merge(arr, mid);
31+
}
32+
}
33+
34+
pub fn bottom_up_merge_sort_inplace<T: Ord>(a: &mut [T]) {
35+
if a.len() > 1 {
36+
let len: usize = a.len();
37+
let mut sub_array_size: usize = 1;
38+
while sub_array_size < len {
39+
let mut start_index: usize = 0;
40+
// still have more than one sub-arrays to merge
41+
while len - start_index > sub_array_size {
42+
let end_idx: usize = if start_index + 2 * sub_array_size > len {
43+
len
44+
} else {
45+
start_index + 2 * sub_array_size
46+
};
47+
// merge a[start_index..start_index+sub_array_size] and a[start_index+sub_array_size..end_idx]
48+
// NOTE: mid is a relative index number starting from `start_index`
49+
merge(&mut a[start_index..end_idx], sub_array_size);
50+
// update `start_index` to merge the next sub-arrays
51+
start_index = end_idx;
52+
}
53+
sub_array_size *= 2;
54+
}
55+
}
56+
}
57+
58+
#[cfg(test)]
59+
mod tests {
60+
#[cfg(test)]
61+
mod top_down_merge_sort {
62+
use super::super::*;
63+
use crate::sorting::have_same_elements;
64+
use crate::sorting::is_sorted;
65+
66+
#[test]
67+
fn basic() {
68+
let mut res = vec![10, 8, 4, 3, 1, 9, 2, 7, 5, 6];
69+
let cloned = res.clone();
70+
top_down_merge_sort_inplace(&mut res);
71+
assert!(is_sorted(&res) && have_same_elements(&res, &cloned));
72+
}
73+
74+
#[test]
75+
fn basic_string() {
76+
let mut res = vec!["a", "bb", "d", "cc"];
77+
let cloned = res.clone();
78+
top_down_merge_sort_inplace(&mut res);
79+
assert!(is_sorted(&res) && have_same_elements(&res, &cloned));
80+
}
81+
82+
#[test]
83+
fn empty() {
84+
let mut res = Vec::<u8>::new();
85+
let cloned = res.clone();
86+
top_down_merge_sort_inplace(&mut res);
87+
assert!(is_sorted(&res) && have_same_elements(&res, &cloned));
88+
}
89+
90+
#[test]
91+
fn one_element() {
92+
let mut res = vec![1];
93+
let cloned = res.clone();
94+
top_down_merge_sort_inplace(&mut res);
95+
assert!(is_sorted(&res) && have_same_elements(&res, &cloned));
96+
}
97+
98+
#[test]
99+
fn pre_sorted() {
100+
let mut res = vec![1, 2, 3, 4];
101+
let cloned = res.clone();
102+
top_down_merge_sort_inplace(&mut res);
103+
assert!(is_sorted(&res) && have_same_elements(&res, &cloned));
104+
}
105+
106+
#[test]
107+
fn reverse_sorted() {
108+
let mut res = vec![4, 3, 2, 1];
109+
let cloned = res.clone();
110+
top_down_merge_sort_inplace(&mut res);
111+
assert!(is_sorted(&res) && have_same_elements(&res, &cloned));
112+
}
113+
}
114+
115+
#[cfg(test)]
116+
mod bottom_up_merge_sort {
117+
use super::super::*;
118+
use crate::sorting::have_same_elements;
119+
use crate::sorting::is_sorted;
120+
121+
#[test]
122+
fn basic() {
123+
let mut res = vec![10, 8, 4, 3, 1, 9, 2, 7, 5, 6];
124+
let cloned = res.clone();
125+
bottom_up_merge_sort_inplace(&mut res);
126+
assert!(is_sorted(&res) && have_same_elements(&res, &cloned));
127+
}
128+
129+
#[test]
130+
fn basic_string() {
131+
let mut res = vec!["a", "bb", "d", "cc"];
132+
let cloned = res.clone();
133+
bottom_up_merge_sort_inplace(&mut res);
134+
assert!(is_sorted(&res) && have_same_elements(&res, &cloned));
135+
}
136+
137+
#[test]
138+
fn empty() {
139+
let mut res = Vec::<u8>::new();
140+
let cloned = res.clone();
141+
bottom_up_merge_sort_inplace(&mut res);
142+
assert!(is_sorted(&res) && have_same_elements(&res, &cloned));
143+
}
144+
145+
#[test]
146+
fn one_element() {
147+
let mut res = vec![1];
148+
let cloned = res.clone();
149+
bottom_up_merge_sort_inplace(&mut res);
150+
assert!(is_sorted(&res) && have_same_elements(&res, &cloned));
151+
}
152+
153+
#[test]
154+
fn pre_sorted() {
155+
let mut res = vec![1, 2, 3, 4];
156+
let cloned = res.clone();
157+
bottom_up_merge_sort_inplace(&mut res);
158+
assert!(is_sorted(&res) && have_same_elements(&res, &cloned));
159+
}
160+
161+
#[test]
162+
fn reverse_sorted() {
163+
let mut res = vec![4, 3, 2, 1];
164+
let cloned = res.clone();
165+
bottom_up_merge_sort_inplace(&mut res);
166+
assert!(is_sorted(&res) && have_same_elements(&res, &cloned));
167+
}
168+
}
169+
}

src/sorting/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ mod heap_sort;
1616
mod insertion_sort;
1717
mod intro_sort;
1818
mod merge_sort;
19+
mod merge_sort_inplace;
1920
mod odd_even_sort;
2021
mod pancake_sort;
2122
mod patience_sort;
@@ -54,6 +55,8 @@ pub use self::insertion_sort::insertion_sort;
5455
pub use self::intro_sort::intro_sort;
5556
pub use self::merge_sort::bottom_up_merge_sort;
5657
pub use self::merge_sort::top_down_merge_sort;
58+
pub use self::merge_sort_inplace::bottom_up_merge_sort_inplace;
59+
pub use self::merge_sort_inplace::top_down_merge_sort_inplace;
5760
pub use self::odd_even_sort::odd_even_sort;
5861
pub use self::pancake_sort::pancake_sort;
5962
pub use self::patience_sort::patience_sort;
@@ -69,7 +72,6 @@ pub use self::tim_sort::tim_sort;
6972
pub use self::tree_sort::tree_sort;
7073
pub use self::wave_sort::wave_sort;
7174
pub use self::wiggle_sort::wiggle_sort;
72-
7375
#[cfg(test)]
7476
use std::cmp;
7577

0 commit comments

Comments
 (0)