devela/data/sort/
generic.rs

1// devela::data::sort::impl_generic
2//
3//! Implements sorting algorithms for exclusive generic arrays `[T: Ord; N]`.
4//
5
6use crate::{iif, Sort};
7#[cfg(feature = "alloc")]
8use crate::{BTreeMap, Vec};
9
10impl<T: Ord> Sort<&mut [T]> {
11    /// Sorts a slice using bubble sort.
12    ///
13    /// # Examples
14    /// ```
15    /// # use devela::Sort;
16    /// let mut data = [4, 7, -5, 1, -13, 0];
17    /// Sort(&mut data[..]).bubble();
18    /// assert_eq![data, [-13, -5, 0, 1, 4, 7]];
19    /// ```
20    pub fn bubble(self) {
21        for i in 0..self.0.len() {
22            for j in 0..self.0.len() - i - 1 {
23                iif![self.0[j] > self.0[j + 1]; self.0.swap(j, j + 1)];
24            }
25        }
26    }
27
28    /// Sorts a slice using counting sort, and returns the ordered frequencies.
29    ///
30    /// Counting sort is particularly efficient when the range of input values is
31    /// small compared to the number of elements to be sorted.
32    ///
33    /// # Examples
34    /// ```
35    /// # use devela::Sort;
36    /// let mut data = [4, 64, 4, 2, 4, 8, 8, 4, 8, 4, 2, 8, 64, 4, 8, 4, 2];
37    /// let freq = Sort(&mut data[..]).counting();
38    /// assert_eq![data, [2, 2, 2, 4, 4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 64, 64]];
39    /// assert_eq![freq, [3, 7, 5, 2]];
40    /// ```
41    #[cfg(feature = "alloc")]
42    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "alloc")))]
43    pub fn counting(self) -> Vec<usize>
44    where
45        T: Clone,
46    {
47        let mut counts = BTreeMap::new();
48        // Calculate the frequencies and save them
49        for item in self.0.iter() {
50            let count = counts.entry(item.clone()).or_insert(0);
51            *count += 1;
52        }
53        let freq: Vec<usize> = counts.values().copied().collect();
54        // Reconstruct the sorted slice
55        let mut i = 0;
56        for (item, &count) in counts.iter() {
57            for _ in 0..count {
58                self.0[i] = item.clone();
59                i += 1;
60            }
61        }
62        freq
63    }
64
65    /// Sorts a slice using counting sort, and writes the frequencies, without allocating.
66    ///
67    /// Counting sort is particularly efficient when the range of input values is
68    /// small compared to the number of elements to be sorted.
69    ///
70    /// This implementation makes the following assumptions:
71    /// - `values` contains all distinct values present in `self`.
72    /// - `freq` and `values` are of the same length.
73    /// - `freq` only contains zeros.
74    ///
75    /// Returns `None` if `values` does not contain a value present in `self`,
76    /// or if `self` has more elements than `freq` can accommodate.
77    ///
78    /// Note that the frequencies in `freq` will be in the order of the sorted
79    /// distinct elements in `values`.
80    ///
81    /// # Examples
82    /// ```
83    /// # use devela::Sort;
84    /// let mut data = [4, 64, 4, 2, 4, 8, 8, 4, 8, 4, 2, 8, 64, 4, 8, 4, 2];
85    /// let values = [64, 4, 2, 8];
86    /// let mut freq = [0; 4];
87    /// Sort(&mut data[..]).counting_buf(&mut freq, &values);
88    /// assert_eq![data, [64, 64, 4, 4, 4, 4, 4, 4, 4, 2, 2, 2, 8, 8, 8, 8, 8]];
89    /// assert_eq![freq, [2, 7, 3, 5]];
90    /// ```
91    /// # Panics
92    /// Panics in debug if the length of `freq` and `values` is not the same.
93    pub fn counting_buf(self, freq: &mut [T], values: &[T]) -> Option<()>
94    where
95        T: Clone + TryInto<usize> + TryFrom<usize>,
96    {
97        debug_assert_eq![freq.len(), values.len()];
98        // Calculate the frequencies
99        for item in self.0.iter() {
100            let index = values.iter().position(|x| x == item)?;
101            let count: usize = freq[index].clone().try_into().ok()?;
102            freq[index] = T::try_from(count + 1).ok()?;
103        }
104        // Reconstruct the sorted slice
105        let mut i = 0;
106        for (index, count) in freq.iter().enumerate() {
107            for _ in 0_usize..(*count).clone().try_into().ok()? {
108                if i >= self.0.len() {
109                    return None; // Out of bounds
110                }
111                self.0[i] = values[index].clone();
112                i += 1;
113            }
114        }
115        Some(())
116    }
117
118    /// Sorts a slice using insertion sort.
119    ///
120    /// # Examples
121    /// ```
122    /// # use devela::Sort;
123    /// let mut arr = [4, 7, -5, 1, -13, 0];
124    /// Sort(&mut arr[..]).insertion();
125    /// assert_eq![arr, [-13, -5, 0, 1, 4, 7]];
126    /// ```
127    pub fn insertion(self) {
128        for i in 1..self.0.len() {
129            let mut j = i;
130            while j > 0 && self.0[j - 1] > self.0[j] {
131                self.0.swap(j, j - 1);
132                j -= 1;
133            }
134        }
135    }
136
137    /// Sorts a `slice` using merge sort.
138    ///
139    /// It allocates one vector for the entire sort operation.
140    ///
141    /// # Examples
142    /// ```
143    /// # use devela::Sort;
144    /// let mut arr = [4, 7, -5, 1, -13, 0];
145    /// Sort(&mut arr[..]).merge();
146    /// assert_eq![arr, [-13, -5, 0, 1, 4, 7]];
147    /// ```
148    #[cfg(feature = "alloc")]
149    #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = "alloc")))]
150    pub fn merge(self)
151    where
152        T: Copy,
153    {
154        let len = self.0.len();
155        let mut buffer = Vec::with_capacity(len);
156        buffer.resize(len, self.0[0]);
157        helper::sort_merge_internal(self.0, &mut buffer);
158    }
159
160    /// Sorts a slice using selection sort.
161    ///
162    /// # Examples
163    /// ```
164    /// # use devela::Sort;
165    /// let mut arr = [4, 7, -5, 1, -13, 0];
166    /// Sort(&mut arr[..]).selection();
167    /// assert_eq![arr, [-13, -5, 0, 1, 4, 7]];
168    /// ```
169    pub fn selection(self) {
170        let len = self.0.len();
171        for i in 0..len - 1 {
172            let mut min_index = i;
173            for j in (i + 1)..len {
174                iif![self.0[j] < self.0[min_index]; min_index = j];
175            }
176            self.0.swap(min_index, i);
177        }
178    }
179
180    /// Sorts a slice using shaker sort.
181    ///
182    /// Also known as cocktail sort and double quicksort.
183    ///
184    /// # Examples
185    /// ```
186    /// # use devela::Sort;
187    /// let mut arr = [4, 7, -5, 1, -13, 0];
188    /// Sort(&mut arr[..]).shaker();
189    /// assert_eq![arr, [-13, -5, 0, 1, 4, 7]];
190    /// ```
191    pub fn shaker(self)
192    where
193        T: Clone,
194    {
195        let (mut swapped, mut start, mut end) = (true, 0, self.0.len());
196        while swapped {
197            swapped = false;
198            for i in start..end - 1 {
199                iif![self.0[i] > self.0[i + 1]; { self.0.swap(i, i + 1); swapped = true; }];
200            }
201            iif![!swapped; break];
202            swapped = false;
203            end -= 1;
204            for i in (start..end - 1).rev() {
205                iif![self.0[i] > self.0[i + 1]; { self.0.swap(i, i + 1); swapped = true; }];
206            }
207            start += 1;
208        }
209    }
210}
211
212impl<'a, T: Ord + 'a> Sort<&'a mut [T]> {
213    /// Sorts a `slice` using quick sort with the Lomuto partition scheme.
214    ///
215    /// It performs more swaps compared to the Hoare partition scheme.
216    ///
217    /// # Examples
218    /// ```
219    /// # use devela::Sort;
220    /// let mut arr = [4, 7, -5, 1, -13, 0];
221    /// // Sort(&mut arr[..]).quick_lomuto();
222    /// Sort::quick_lomuto(&mut arr[..]);
223    /// assert_eq![arr, [-13, -5, 0, 1, 4, 7]];
224    /// ```
225    pub fn quick_lomuto(slice: &mut [T]) {
226        iif![slice.len() < 2; return];
227        let ipivot = helper::sort_quick_lomuto_partition(slice);
228        Self::quick_lomuto(&mut slice[0..ipivot]);
229        Self::quick_lomuto(&mut slice[ipivot + 1..]);
230    }
231    // NOTE: can't use self because of multiple mutable borrows
232    // pub fn quick_lomuto(self) {
233    //     iif![self.0.len() < 2; return];
234    //     let ipivot = helper::sort_quick_lomuto_partition(self.0);
235    //     Self(&mut self.0[0..ipivot]).quick_lomuto();
236    //     Self(&mut self.0[ipivot + 1..]).quick_lomuto();
237    // }
238
239    /// Sorts a `slice` using quick sort with the Three way partition scheme.
240    ///
241    /// It is more efficient when dealing with duplicate elements.
242    ///
243    /// # Examples
244    /// ```
245    /// # use devela::Sort;
246    /// let mut arr = [4, 7, -5, 1, -13, 0];
247    /// Sort::quick_3way(&mut arr);
248    /// assert_eq![arr, [-13, -5, 0, 1, 4, 7]];
249    /// ```
250    pub fn quick_3way(slice: &mut [T])
251    where
252        T: Clone,
253    {
254        let len = slice.len();
255        iif![len < 2; return];
256        let (lt, gt) = helper::sort_quick_3way_partition(slice);
257        Self::quick_3way(&mut slice[0..lt]);
258        iif![gt < len; Self::quick_3way(&mut slice[gt..])];
259    }
260    // NOTE: can't use self because of multiple mutable borrows
261    // pub fn quick_3way(self) where T: Clone {
262    //     let len = self.0.len();
263    //     iif![len < 2; return];
264    //     let (lt, gt) = helper::sort_quick_3way_partition(self.0);
265    //     Self(&mut self.0[0..lt]).quick_3way();
266    //     iif![gt < len; Self(&mut self.0[gt..]).quick_3way()];
267    // }
268
269    /// Sorts a `slice` using quick sort with the Hoare partition scheme.
270    ///
271    /// It performs fewer swaps compared to the Lomuto partition scheme.
272    ///
273    /// # Examples
274    /// ```
275    /// # use devela::Sort;
276    /// let mut arr = [4, 7, -5, 1, -13, 0];
277    /// Sort::quick_hoare(&mut arr);
278    /// assert_eq![arr, [-13, -5, 0, 1, 4, 7]];
279    /// ```
280    pub fn quick_hoare(slice: &mut [T])
281    where
282        T: Clone,
283    {
284        let len = slice.len();
285        iif![len < 2; return];
286        let ipivot = helper::sort_quick_hoare_partition(slice);
287        iif![ipivot > 0; Self::quick_hoare(&mut slice[0..ipivot])];
288        iif![ipivot + 1 < len; Self::quick_hoare(&mut slice[ipivot + 1..])];
289    }
290    // NOTE: can't use self because of multiple mutable borrows
291    // pub fn quick_hoare(self) where T: Clone {
292    //     let len = self.0.len();
293    //     iif![len < 2; return];
294    //     let ipivot = helper::sort_quick_hoare_partition(self.0);
295    //     iif![ipivot > 0; Self(&mut self.0[0..ipivot]).quick_hoare()];
296    //     iif![ipivot + 1 < len; Self(&mut self.0[ipivot + 1..]).quick_hoare()];
297    // }
298}
299
300// private helper fns
301mod helper {
302    use crate::{iif, sf, Ordering};
303
304    #[cfg(feature = "alloc")]
305    pub(super) fn sort_merge_internal<T: Ord + Copy>(slice: &mut [T], buffer: &mut [T]) {
306        let len = slice.len();
307        iif![len <= 1; return];
308        let mid = len / 2;
309        sort_merge_internal(&mut slice[..mid], buffer);
310        sort_merge_internal(&mut slice[mid..], buffer);
311        sort_merge_merge(&slice[..mid], &slice[mid..], &mut buffer[..len]);
312        slice.copy_from_slice(&buffer[..len]);
313    }
314    #[cfg(feature = "alloc")]
315    pub(super) fn sort_merge_merge<T: Ord + Copy>(left: &[T], right: &[T], slice: &mut [T]) {
316        let (mut i, mut j, mut k) = (0, 0, 0);
317        while i < left.len() && j < right.len() {
318            iif![ left[i] < right[j] ;
319                { slice[k] = left[i]; i += 1; } ;
320                { slice[k] = right[j]; j += 1; }
321            ];
322            k += 1;
323        }
324        iif![i < left.len(); slice[k..].copy_from_slice(&left[i..])];
325        iif![j < right.len(); slice[k..].copy_from_slice(&right[j..])];
326    }
327    pub(super) fn sort_quick_lomuto_partition<T: Ord>(slice: &mut [T]) -> usize {
328        let len = slice.len();
329        let ipivot = len / 2;
330        slice.swap(ipivot, len - 1);
331        let mut i = 0;
332        for j in 0..len - 1 {
333            iif![slice[j] <= slice[len - 1]; { slice.swap(i, j); i += 1; }];
334        }
335        slice.swap(i, len - 1);
336        i
337    }
338    pub(super) fn sort_quick_3way_partition<T: Ord + Clone>(slice: &mut [T]) -> (usize, usize) {
339        let len = slice.len();
340        let ipivot = len / 2;
341        let pivot = slice[ipivot].clone();
342        let (mut lt, mut gt, mut i) = (0, len, 0);
343        while i < gt {
344            match slice[i].cmp(&pivot) {
345                Ordering::Less => {
346                    slice.swap(lt, i);
347                    lt += 1;
348                    i += 1;
349                }
350                Ordering::Greater => {
351                    gt -= 1;
352                    slice.swap(i, gt);
353                }
354                Ordering::Equal => i += 1,
355            }
356        }
357        (lt, gt)
358    }
359    pub(super) fn sort_quick_hoare_partition<T: Ord + Clone>(slice: &mut [T]) -> usize {
360        let len = slice.len();
361        let ipivot = len / 2;
362        let pivot = slice[ipivot].clone();
363        let (mut i, mut j) = (0, len - 1);
364        loop {
365            sf! {
366                while slice[i] < pivot { i += 1; }
367                while slice[j] > pivot { j -= 1; }
368            }
369            iif![i >= j; return j];
370            slice.swap(i, j);
371        }
372    }
373}