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}