Skip to content

Commit 128e911

Browse files
hosseind88hossein.dindarsiriak
authored
Add tim sort (rust-lang#273)
Co-authored-by: hossein.dindar <hossein.dindar@arvancloud.com> Co-authored-by: Andrii Siriak <siryaka@gmail.com>
1 parent e95676f commit 128e911

File tree

3 files changed

+145
-0
lines changed

3 files changed

+145
-0
lines changed

src/sorting/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,15 @@ From [Wikipedia][stooge-wiki]: Stooge sort is a recursive sorting algorithm. It
158158
__Properties__
159159
* Worst case performance O(n^(log(3) / log(1.5)))
160160

161+
### [Tim](./tim_sort.rs)
162+
![alt text][tim-image]
163+
164+
From [Wikipedia][tim-wiki]: Timsort is a hybrid stable sorting algorithm, derived from merge sort and insertion sort, designed to perform well on many kinds of real-world data. It was implemented by Tim Peters in 2002 for use in the Python programming language. The algorithm finds subsequences of the data that are already ordered (runs) and uses them to sort the remainder more efficiently. This is done by merging runs until certain criteria are fulfilled. Timsort has been Python's standard sorting algorithm since version 2.3. It is also used to sort arrays of non-primitive type in Java SE 7, on the Android platform, in GNU Octave, on V8, Swift, and Rust.
165+
166+
__Properties__
167+
* Worst-case performance O(n log n)
168+
* Best-case performance O(n)
169+
161170
[bubble-toptal]: https://www.toptal.com/developers/sorting-algorithms/bubble-sort
162171
[bubble-wiki]: https://en.wikipedia.org/wiki/Bubble_sort
163172
[bubble-image]: https://upload.wikimedia.org/wikipedia/commons/thumb/8/83/Bubblesort-edited-color.svg/220px-Bubblesort-edited-color.svg.png "Bubble Sort"
@@ -199,5 +208,8 @@ __Properties__
199208
[stooge-image]: https://upload.wikimedia.org/wikipedia/commons/f/f8/Sorting_stoogesort_anim.gif
200209
[stooge-wiki]: https://en.wikipedia.org/wiki/Stooge_sort
201210

211+
[tim-image]: https://thumbs.gfycat.com/BruisedFrigidBlackrhino-size_restricted.gif
212+
[tim-wiki]: https://en.wikipedia.org/wiki/Timsort
213+
202214
[comb-sort]: https://upload.wikimedia.org/wikipedia/commons/4/46/Comb_sort_demo.gif
203215
[comb-sort-wiki]: https://en.wikipedia.org/wiki/Comb_sort

src/sorting/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ mod radix_sort;
1313
mod selection_sort;
1414
mod shell_sort;
1515
mod stooge_sort;
16+
mod tim_sort;
1617

1718
pub use self::bubble_sort::bubble_sort;
1819
pub use self::bucket_sort::bucket_sort;
@@ -30,6 +31,7 @@ pub use self::radix_sort::radix_sort;
3031
pub use self::selection_sort::selection_sort;
3132
pub use self::shell_sort::shell_sort;
3233
pub use self::stooge_sort::stooge_sort;
34+
pub use self::tim_sort::tim_sort;
3335

3436
use std::cmp;
3537

src/sorting/tim_sort.rs

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
use std::cmp;
2+
3+
static MIN_MERGE: usize = 32;
4+
5+
fn min_run_length(mut n: usize) -> usize {
6+
let mut r = 0;
7+
while n >= MIN_MERGE {
8+
r |= n & 1;
9+
n >>= 1;
10+
}
11+
n + r
12+
}
13+
14+
fn insertion_sort(arr: &mut Vec<i32>, left: usize, right: usize) -> &Vec<i32> {
15+
for i in (left + 1)..(right + 1) {
16+
let temp = arr[i];
17+
let mut j = (i - 1) as i32;
18+
19+
while j >= (left as i32) && arr[j as usize] > temp {
20+
arr[(j + 1) as usize] = arr[j as usize];
21+
j -= 1;
22+
}
23+
arr[(j + 1) as usize] = temp;
24+
}
25+
arr
26+
}
27+
28+
fn merge(arr: &mut Vec<i32>, l: usize, m: usize, r: usize) -> &Vec<i32> {
29+
let len1 = m - l + 1;
30+
let len2 = r - m;
31+
let mut left = vec![0; len1 as usize];
32+
let mut right = vec![0; len2 as usize];
33+
34+
left[..len1].clone_from_slice(&arr[l..(len1 + l)]);
35+
36+
for x in 0..len2 {
37+
right[x] = arr[m + 1 + x];
38+
}
39+
40+
let mut i = 0;
41+
let mut j = 0;
42+
let mut k = l;
43+
44+
while i < len1 && j < len2 {
45+
if left[i] <= right[j] {
46+
arr[k] = left[i];
47+
i += 1;
48+
} else {
49+
arr[k] = right[j];
50+
j += 1;
51+
}
52+
k += 1;
53+
}
54+
55+
while i < len1 {
56+
arr[k] = left[i];
57+
k += 1;
58+
i += 1;
59+
}
60+
61+
while j < len2 {
62+
arr[k] = right[j];
63+
k += 1;
64+
j += 1;
65+
}
66+
arr
67+
}
68+
69+
pub fn tim_sort(arr: &mut Vec<i32>, n: usize) {
70+
let min_run = min_run_length(MIN_MERGE) as usize;
71+
72+
let mut i = 0;
73+
while i < n {
74+
insertion_sort(arr, i, cmp::min(i + MIN_MERGE - 1, n - 1));
75+
i += min_run;
76+
}
77+
78+
let mut size = min_run;
79+
while size < n {
80+
let mut left = 0;
81+
while left < n {
82+
let mid = left + size - 1;
83+
let right = cmp::min(left + 2 * size - 1, n - 1);
84+
if mid < right {
85+
merge(arr, left, mid, right);
86+
}
87+
88+
left += 2 * size;
89+
}
90+
size *= 2;
91+
}
92+
}
93+
94+
#[cfg(test)]
95+
mod tests {
96+
use super::*;
97+
98+
#[test]
99+
fn basic() {
100+
let mut array = vec![-2, 7, 15, -14, 0, 15, 0, 7, -7, -4, -13, 5, 8, -14, 12];
101+
let arr_len = array.len();
102+
tim_sort(&mut array, arr_len);
103+
for i in 0..array.len() - 1 {
104+
assert!(array[i] <= array[i + 1]);
105+
}
106+
}
107+
108+
#[test]
109+
fn empty() {
110+
let mut array = Vec::<i32>::new();
111+
let arr_len = array.len();
112+
tim_sort(&mut array, arr_len);
113+
assert_eq!(array, vec![]);
114+
}
115+
116+
#[test]
117+
fn one_element() {
118+
let mut array = vec![3];
119+
let arr_len = array.len();
120+
tim_sort(&mut array, arr_len);
121+
assert_eq!(array, vec![3]);
122+
}
123+
124+
#[test]
125+
fn pre_sorted() {
126+
let mut array = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
127+
let arr_len = array.len();
128+
tim_sort(&mut array, arr_len);
129+
assert_eq!(array, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
130+
}
131+
}

0 commit comments

Comments
 (0)