Skip to main content

search_sort/
sort.rs

1//! Implementations of sorting algorithms.
2
3use std::cmp::Ordering;
4
5/// Checks if a slice is sorted.
6pub fn test<T: Ord>(slice: &[T]) -> bool {
7    if slice.len() < 2 {
8        return true;
9    }
10
11    let mut iter = slice.iter();
12    let mut prev = iter.next().unwrap();
13    let mut curr = iter.next();
14
15    while curr != None {
16        let value = curr.unwrap();
17        if prev > value {
18            return false;
19        }
20
21        prev = value;
22        curr = iter.next();
23    }
24
25    true
26}
27
28/// Alias for [`test()`].
29pub fn is_sorted<T: Ord>(slice: &[T]) -> bool {
30    test(slice)
31}
32
33/// An implementation of bubble sort.
34///
35/// Checks for every element if the next element is greater than this and swaps
36/// them if so. Then repeats the process until the list is sorted.
37///
38/// # Examples
39/// ```
40/// use search_sort::sort;
41///
42/// let mut slice = [1, 6, 3, -44, 11, 2];
43/// sort::bubble(&mut slice);
44/// assert_eq!(slice, [-44, 1, 2, 3, 6, 11]);
45/// ```
46pub fn bubble<T: Ord>(slice: &mut [T]) {
47    if test(slice) {
48        return;
49    }
50
51    let mut n = slice.len();
52    while n > 1 {
53        let mut newn = 0;
54
55        for i in 1..n {
56            if slice[i - 1] > slice[i] {
57                slice.swap(i - 1, i);
58                newn = i;
59            }
60        }
61
62        n = newn;
63    }
64}
65
66/// Part of quick sort algorithm.
67///
68/// Sets the pivot, places smaller elements before it and greater after it.
69/// Returns the final position of the pivot.
70///
71/// This function is used in [`quick`] sort.
72pub fn quick_partition<T: Ord>(slice: &mut [T]) -> usize {
73    // 'the pivot' is the last element of the slice
74
75    let n = slice.len();
76    let mut lo = 0;
77    let mut hi = n - 1;
78    let mut pivot = n - 1;
79
80    let mut equal = false;
81    loop {
82        // always increments the counter if they're equal
83        if equal {
84            lo += 1;
85            equal = false;
86        }
87
88        // search for an element greater or equal to the pivot
89        while slice[lo] < slice[pivot] {
90            lo += 1;
91        }
92
93        // search for an element smaller or equal to the pivot
94        while hi > 0 && slice[hi] > slice[pivot] {
95            hi -= 1;
96        }
97
98        if lo >= hi {
99            // the slice is sorted
100            break;
101        } else if slice[lo] == slice[hi] {
102            equal = true;
103        } else {
104            if lo == pivot {
105                pivot = hi;
106            } else if hi == pivot {
107                pivot = lo;
108            }
109
110            slice.swap(lo, hi);
111        }
112    }
113
114    slice.swap(lo, pivot);
115    lo
116}
117
118/// An implementation of quick sort.
119///
120/// Partitions the slice into two parts by [`quick_partition`], and invokes
121/// itself until the list is sorted.
122///
123/// # Examples
124/// ```
125/// use search_sort::sort;
126///
127/// let mut slice = [5, 1, -5, 3, 9, 2, 19];
128/// sort::quick(&mut slice);
129/// assert_eq!(slice, [-5, 1, 2, 3, 5, 9, 19]);
130/// ```
131pub fn quick<T: Ord>(slice: &mut [T]) {
132    if test(slice) {
133        return;
134    }
135    let partition = quick_partition(slice);
136    quick(&mut slice[..partition]);
137    quick(&mut slice[(partition + 1)..]);
138}
139
140/// An implemetation of top-down (recursive) merge sort that uses only
141/// half of the space.
142///
143/// Invokes itself on the two halves, copies the first half of the slice and
144/// merges it into the original slice.
145///
146/// # Examples
147/// ```
148/// use search_sort::sort;
149///
150/// let mut slice = [4, -2, 7, 0, 11, -11, -10];
151/// sort::merge(&mut slice);
152/// assert_eq!(slice, [-11, -10, -2, 0, 4, 7, 11]);
153/// ```
154pub fn merge<T: Ord + Clone>(slice: &mut [T]) {
155    if test(slice) {
156        return;
157    }
158
159    let mid = slice.len() / 2;
160
161    // copy first part to a new slice
162    let mut left = Vec::new();
163    left.extend_from_slice(&slice[..mid]);
164    let mut left = &mut left[..];
165
166    merge(&mut left);
167    merge(&mut slice[mid..]);
168
169    // merge the two parts
170    let mut i = 0;
171    let mut j = 0;
172    loop {
173        let midj = mid + j;
174
175        if i == mid {
176            // the slice is sorted, as the first part has been merged
177            break;
178        } else if midj == slice.len() {
179            // only the second half has been merged, so clone the remainging
180            // elements
181            slice[(mid + i)..].clone_from_slice(&left[i..]);
182            break;
183        }
184
185        let ij = i + j;
186
187        match left[i].cmp(&slice[midj]) {
188            Ordering::Less => {
189                slice[ij] = left[i].clone();
190                i += 1;
191            }
192            Ordering::Equal => {
193                // insert the two elements one by one, since they are equal
194
195                let e = left[i].clone();
196
197                slice[ij] = e.clone();
198                slice[ij + 1] = e;
199
200                i += 1;
201                j += 1;
202            }
203            Ordering::Greater => {
204                slice[i + j] = slice[midj].clone();
205                j += 1;
206            }
207        }
208    }
209}
210
211#[cfg(test)]
212mod tests {
213    use super::bubble;
214    use super::merge;
215    use super::quick;
216    use super::test;
217
218    #[test]
219    fn test_test() {
220        // lol
221        assert!(test(&[0, 3, 4, 10, 12]));
222        assert!(!test(&[6, 2, 1, 10, -2]));
223    }
224
225    #[test]
226    fn bubble_test() {
227        let mut data = [4, 2, 1, 8, 7, 9, -11];
228        bubble(&mut data);
229        assert_eq!(data, [-11, 1, 2, 4, 7, 8, 9]);
230    }
231
232    #[test]
233    fn quick_test() {
234        let mut data = [6, 7, 3, 5, 4, -12];
235        quick(&mut data);
236        assert_eq!(data, [-12, 3, 4, 5, 6, 7]);
237    }
238
239    #[test]
240    fn merge_test() {
241        let mut data1 = [6, 1, 2, 99, -1, 13, 7, 1];
242        let mut data2 = [5, 7, 11, -1, 2, 3];
243        let mut data3 = [11, 16, 20, 12, 13, 15];
244
245        merge(&mut data1);
246        merge(&mut data2);
247        merge(&mut data3);
248
249        assert_eq!(data1, [-1, 1, 1, 2, 6, 7, 13, 99]);
250        assert_eq!(data2, [-1, 2, 3, 5, 7, 11]);
251        assert_eq!(data3, [11, 12, 13, 15, 16, 20]);
252    }
253}