a/sort/selection.rs
1use core::cmp::Ordering::{Equal, Greater, Less};
2
3/// Sorts a slice in place using double-ended selection sort.
4///
5/// Each pass scans the unsorted middle of the slice once, finds both its smallest and its
6/// largest key, moves every element holding the smallest key to the front of that range and
7/// every element holding the largest key to its back. Those elements are then in their final
8/// places, so the next pass scans only what lies between them.
9///
10/// Three refinements keep the algorithm as cheap as selection sort can be:
11///
12/// * **Pairwise min-max scan.** Elements are taken two at a time: the two are compared with
13/// each other first, then only the smaller one is compared with the running minimum and
14/// only the larger one with the running maximum. A range of `m` elements costs
15/// `⌈3m/2⌉ - 2` comparisons per pass instead of the `2m - 2` of two independent scans,
16/// which is the fewest any algorithm can use to find both extremes.
17/// * **Duplicate gathering ("bingo") for free.** Every comparison is a three-way
18/// [`Ord::cmp`], so an element equal to the running minimum or maximum is recognised
19/// without an extra comparison and joins that key's group. A pass therefore retires all
20/// copies of two keys: input with `k` distinct keys finishes in at most `⌈k/2⌉` passes
21/// instead of `⌊n/2⌋`. A pass in which every comparison reports [`Equal`] has proved the whole range
22/// equal and ends the sort, again at no extra cost. An equal pair also skips the
23/// comparison with the maximum whenever its minimum comparison already rules that out.
24/// * **Lazy placement.** A running minimum or maximum that has no duplicate yet is only
25/// remembered by index; elements are moved once a pass is over, or when a second copy of
26/// the current extreme turns up. Input with distinct keys costs at most `n - 1` swaps,
27/// exactly like classic selection sort, and gathering duplicates never costs a comparison.
28///
29/// Distinct keys get no benefit from the refinements beyond the pairwise scan, so the worst
30/// case is any input with distinct keys, and on such input the number of comparisons
31/// depends only on `n`: `n(3n - 2)/8` for even `n` and `3(n² - 1)/8` for odd `n`, about 25%
32/// fewer than the `n(n - 1)/2` of classic selection sort.
33///
34/// # Properties
35///
36/// * **Not stable**: equal elements may be reordered.
37/// * **In place**: `O(1)` auxiliary memory, no allocation.
38/// * **Not adaptive to order**: sorted input costs as much as any other with distinct keys.
39/// It is adaptive to duplicates instead: the fewer distinct keys, the fewer passes.
40///
41/// | Case | Comparisons | Swaps |
42/// |-------------------------------|-------------------------------------|----------------|
43/// | Best (all elements equal) | `n - 1` | `0` |
44/// | `k` distinct keys | `O(nk)` | `O(nk)` |
45/// | Worst (all keys distinct) | `n(3n - 2)/8` or `3(n² - 1)/8` | `≤ n - 1` |
46///
47/// Gathering duplicates costs at most `2m` swaps in a pass over `m` elements, so input with
48/// many repeated keys trades the `n - 1` swap bound for far fewer comparisons and passes.
49/// Input that is already in non-decreasing order is never moved at all.
50///
51/// Selection sort is quadratic and is mainly of educational value; prefer
52/// [`slice::sort_unstable`] for real workloads.
53///
54/// # Panics
55///
56/// Does not panic by itself. If the [`Ord`] implementation of `T` panics, the panic is
57/// propagated and `arr` is left in an unspecified order, but it still holds every original
58/// element exactly once: elements are only ever exchanged with [`slice::swap`].
59///
60/// # Examples
61///
62/// ```
63/// use a::sort::selection;
64///
65/// let mut v = [5, 1, 4, 2, 8, 0];
66/// selection(&mut v);
67/// assert_eq!(v, [0, 1, 2, 4, 5, 8]);
68///
69/// // Three distinct keys: the first pass retires every 1 and every 3, the second the 2s.
70/// let mut v = [3, 1, 2, 3, 1, 2, 2, 1];
71/// selection(&mut v);
72/// assert_eq!(v, [1, 1, 1, 2, 2, 2, 3, 3]);
73///
74/// let mut words = vec!["pear", "apple", "fig"];
75/// selection(&mut words);
76/// assert_eq!(words, ["apple", "fig", "pear"]);
77/// ```
78pub fn selection<T: Ord>(arr: &mut [T]) {
79 // Everything before `lo` and from `hi` onwards is already in its final position.
80 let (mut lo, mut hi) = (0, arr.len());
81 while hi - lo > 1 {
82 let mut pass = Pass::new(&mut arr[lo..hi]);
83 pass.scan();
84 match pass.finish() {
85 Some((front, back)) => {
86 lo += front;
87 hi -= back;
88 }
89 None => return, // every element still unsorted is equal to every other
90 }
91 }
92}
93
94/// One pass of [`selection`] over the unsorted range `v`.
95///
96/// The scanned prefix `v[..end]` holds the elements equal to the running minimum (the min
97/// group), the elements equal to the running maximum (the max group), and everything else in
98/// no particular order. A group with a single element is only remembered by its index; once
99/// it has two or more, it is kept contiguous:
100///
101/// * the min group occupies `v[..min_len]`, at the front, where it has to end up anyway;
102/// * the max group occupies `v[mb..mb + max_len]`, somewhere after the min group.
103///
104/// While every element scanned so far is equal (`same`), they all belong to the min group and
105/// the max fields are unused.
106struct Pass<'a, T> {
107 v: &'a mut [T],
108 /// Number of elements scanned.
109 end: usize,
110 /// Whether every element scanned so far is equal.
111 same: bool,
112 /// Length of the contiguous min group at the front, or `0` while it is a single element.
113 min_len: usize,
114 /// Index of an element of the min group.
115 mi: usize,
116 /// Length of the contiguous max group, or `0` while it is a single element.
117 max_len: usize,
118 /// Start of the contiguous max group, when there is one.
119 mb: usize,
120 /// Index of an element of the max group.
121 mx: usize,
122 /// Indices of elements still being placed, kept up to date by [`Pass::swap`].
123 held: [usize; 2],
124}
125
126impl<'a, T: Ord> Pass<'a, T> {
127 fn new(v: &'a mut [T]) -> Self {
128 Pass {
129 v,
130 end: 0,
131 same: true,
132 min_len: 0,
133 mi: 0,
134 max_len: 0,
135 mb: 0,
136 mx: 0,
137 held: [0; 2],
138 }
139 }
140
141 /// Scans the whole range, gathering the min and max groups.
142 fn scan(&mut self) {
143 let len = self.v.len();
144 // An odd length starts from a lone element, an even one from a compared pair, so
145 // the rest of the range always splits into whole pairs.
146 if len % 2 == 1 {
147 self.end = 1;
148 } else {
149 self.end = 2;
150 match self.v[0].cmp(&self.v[1]) {
151 Less => {
152 self.same = false;
153 self.mx = 1;
154 }
155 Greater => {
156 self.same = false;
157 self.mi = 1;
158 }
159 Equal => self.push_min(1),
160 }
161 }
162 while self.end < len {
163 let x = self.end;
164 self.end += 2;
165 self.pair(x, x + 1);
166 }
167 }
168
169 /// Classifies the pair at `x` and `y` with at most three comparisons and places it.
170 fn pair(&mut self, x: usize, y: usize) {
171 // Before the first unequal pair, the minimum is also the maximum.
172 let (min, max) = (self.mi, if self.same { self.mi } else { self.mx });
173 match self.v[x].cmp(&self.v[y]) {
174 Equal => {
175 // Both elements share one key, so one comparison against the minimum often
176 // settles both of them.
177 self.held[0] = y;
178 let joined_min = match self.v[x].cmp(&self.v[min]) {
179 Less => {
180 self.new_min(x);
181 true
182 }
183 Equal => {
184 self.push_min(x);
185 true
186 }
187 // Greater than the minimum while everything so far is equal, so it is
188 // also greater than the maximum.
189 Greater if self.same => {
190 self.new_max(x);
191 false
192 }
193 Greater => match self.v[x].cmp(&self.v[max]) {
194 Less => return, // both lie strictly between the extremes
195 Equal => {
196 self.push_max(x);
197 false
198 }
199 Greater => {
200 self.new_max(x);
201 false
202 }
203 },
204 };
205 let y = self.held[0];
206 if joined_min {
207 self.push_min(y);
208 } else {
209 self.push_max(y);
210 }
211 }
212 order => {
213 let (s, l) = if order == Less { (x, y) } else { (y, x) };
214 // Both comparisons are made against the extremes as they were before the
215 // pair, then the smaller element is placed before the larger one.
216 let below = self.v[s].cmp(&self.v[min]);
217 let above = self.v[l].cmp(&self.v[max]);
218 self.held[0] = l;
219 match below {
220 Less => self.new_min(s),
221 Equal => self.push_min(s),
222 Greater => {}
223 }
224 let l = self.held[0];
225 match above {
226 Less => {}
227 // `l` equals the old maximum. If that was also the old minimum, `s` has
228 // just undercut it, which turned the old min group into the max group.
229 Equal => self.push_max(l),
230 Greater => self.new_max(l),
231 }
232 }
233 }
234 }
235
236 /// Makes the element at `src` the new minimum; the old min group becomes ordinary.
237 fn new_min(&mut self, src: usize) {
238 if self.same {
239 // Every element scanned so far was equal, and they are all larger than `src`:
240 // they form the max group now, exactly where they already are.
241 self.same = false;
242 self.max_len = self.min_len;
243 self.mb = 0;
244 self.mx = self.mi;
245 }
246 self.min_len = 0;
247 self.mi = src;
248 }
249
250 /// Makes the element at `src` the new maximum; the old max group becomes ordinary.
251 fn new_max(&mut self, src: usize) {
252 self.same = false;
253 self.max_len = 0;
254 self.mx = src;
255 }
256
257 /// Adds the element at `src`, which equals the minimum, to the min group.
258 fn push_min(&mut self, src: usize) {
259 self.held[1] = src;
260 if self.min_len == 0 {
261 // The minimum's only element so far opens the group at the front of the range.
262 self.make_room_for_min();
263 self.swap(0, self.mi);
264 self.min_len = 1;
265 }
266 self.make_room_for_min();
267 self.swap(self.min_len, self.held[1]);
268 self.min_len += 1;
269 self.mi = 0;
270 }
271
272 /// Frees the slot just after the min group if the max group starts there, by moving the
273 /// max group's first element to just past its end.
274 fn make_room_for_min(&mut self) {
275 // The element being added to the min group belongs to neither group, and it lies
276 // in the scanned prefix but not in front of the max group, so `mb + max_len` is
277 // still inside the scanned prefix.
278 if self.max_len > 0 && self.mb == self.min_len {
279 self.swap(self.mb, self.mb + self.max_len);
280 self.mb += 1;
281 self.mx = self.mb;
282 }
283 }
284
285 /// Adds the element at `src`, which equals the maximum, to the max group.
286 fn push_max(&mut self, src: usize) {
287 if self.max_len == 0 {
288 // The maximum's only element so far opens the group where it already is.
289 self.mb = self.mx;
290 self.max_len = 1;
291 }
292 // Grow the group to the right while that stays inside the scanned prefix. When it
293 // does not, the group ends the prefix and `src` lies before it but after the min
294 // group, so the slot just before the group is free to take.
295 let next = self.mb + self.max_len;
296 let slot = if next < self.end {
297 next
298 } else {
299 self.mb -= 1;
300 self.mb
301 };
302 self.swap(slot, src);
303 self.max_len += 1;
304 self.mx = self.mb;
305 }
306
307 /// Moves the groups into their final places and returns how many elements were placed at
308 /// the front and at the back, or `None` if the whole range turned out to be equal.
309 fn finish(&mut self) -> Option<(usize, usize)> {
310 if self.same {
311 return None;
312 }
313 let len = self.v.len();
314 // The max group goes first: the slot the minimum needs, `v[0]`, may lie inside it.
315 let back = if self.max_len == 0 {
316 self.swap(len - 1, self.mx);
317 1
318 } else {
319 // Only the group's elements outside `v[target..]` move, each into a slot of
320 // `v[target..]` that the group does not already occupy.
321 let (start, count) = (self.mb, self.max_len);
322 let target = len - count;
323 let free = target.max(start + count);
324 for k in 0..(target - start).min(count) {
325 self.swap(start + k, free + k);
326 }
327 count
328 };
329 let front = if self.min_len == 0 {
330 self.swap(0, self.mi);
331 1
332 } else {
333 self.min_len
334 };
335 Some((front, back))
336 }
337
338 /// Swaps two elements and keeps every remembered index pointing at the same element.
339 fn swap(&mut self, a: usize, b: usize) {
340 if a == b {
341 return;
342 }
343 self.v.swap(a, b);
344 let [h0, h1] = &mut self.held;
345 for index in [&mut self.mi, &mut self.mx, h0, h1] {
346 if *index == a {
347 *index = b;
348 } else if *index == b {
349 *index = a;
350 }
351 }
352 }
353}