1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use ManuallyDrop;
use ptr;
/// Sorts a slice in place using gnome sort.
///
/// A gnome walks along the slice comparing each element with the one before it. While they
/// are in order it steps forward; when they are not, it carries the element back, one slot at
/// a time, until it meets an element that is not greater than it or reaches the front. The
/// slice behind the gnome is always sorted, so once it walks off the end the sort is done.
///
/// Two refinements keep the algorithm as cheap as gnome sort can be:
///
/// * **Teleportation.** Classic gnome sort, having carried an element back `d` slots, walks
/// forward again over those `d` slots, comparing every pair on the way, although each of
/// them is already known to be in order. This gnome remembers where it turned back and
/// returns there at once, which saves exactly one comparison per inversion: about half of
/// them on random input, and `n(n - 1)/2` of the `n(n - 1)` on reverse-sorted input.
/// * **Hole shifting instead of swapping.** An element travelling `d` slots is read once, the
/// `d` greater elements it passes are each shifted right by one slot as they are compared
/// with it, and it is written once into its final slot: `d + 1` moves instead of the `3d`
/// moves of `d` swaps.
///
/// The walk back is unrolled four times, so that the loop branch is paid once per four steps
/// and each comparison's element is still in a register when it is shifted; for elements of
/// up to 8 bytes that is up to 1.2 times faster, and no slower for larger ones.
///
/// Every comparison made is one that classic gnome sort also makes, in the same order; only
/// the redundant ones of the walk forward are skipped. With both refinements gnome sort makes
/// the same comparisons and moves as insertion sort with a linear search; [`insertion`] in this
/// crate searches by galloping instead and makes far fewer comparisons.
///
/// [`insertion`]: fn@crate::sort::insertion
///
/// # Properties
///
/// * **Stable**: equal elements keep their relative order (only strictly greater elements
/// are passed).
/// * **In place**: `O(1)` auxiliary memory, no allocation.
/// * **Adaptive**: the cost grows with how far elements are from their sorted positions.
///
/// Let `I` be the number of inversions, `C` the number of elements that move at least one slot
/// left, and `F` the number of elements other than the first that are smaller than every
/// element before them (they are carried all the way to the front, where no comparison is
/// needed to stop). Each passed element moves one slot and removes one inversion, so every
/// inversion costs exactly one comparison and one move.
///
/// | Case | Comparisons | Moves |
/// |---------------------------|---------------------|-----------------------|
/// | Best (already sorted) | `n - 1` | `0` |
/// | Any input | `n - 1 + I - F` | `I + C` |
/// | Average | `≈ n²/4` | `≈ n²/4` |
/// | Worst (reverse sorted) | `n(n - 1)/2` | `n(n + 1)/2 - 1` |
///
/// Gnome sort is quadratic and is mainly of educational value; prefer [`slice::sort`] for
/// real workloads.
///
/// # Panics
///
/// Does not panic by itself. If the [`Ord`] implementation of `T` panics, the panic is
/// propagated and `arr` is left in an unspecified order, but it still holds every original
/// element exactly once: nothing is dropped twice or leaked.
///
/// # Examples
///
/// ```
/// use a::sort::gnome;
///
/// let mut v = [5, 1, 4, 2, 8, 0];
/// gnome(&mut v);
/// assert_eq!(v, [0, 1, 2, 4, 5, 8]);
///
/// // The 0 at the end is carried to the front in a single walk back.
/// let mut v = [1, 2, 3, 4, 5, 0];
/// gnome(&mut v);
/// assert_eq!(v, [0, 1, 2, 3, 4, 5]);
///
/// let mut words = vec!["pear", "apple", "fig"];
/// gnome(&mut words);
/// assert_eq!(words, ["apple", "fig", "pear"]);
/// ```
/// Shifts the element before the vacant slot `hole.dst` into it and makes its old slot the
/// vacant one. Returns whether the walk back is over: the vacant slot has reached `base`, or
/// the element before it is not greater than the carried one.
///
/// # Safety
///
/// `hole.dst` must be the vacant slot of a slice starting at `base`, strictly after `base`.
unsafe
/// An element temporarily moved out of a slice, plus the slot it will be written back to.
///
/// Writing back on drop is what keeps [`gnome`] panic-safe: the slice is whole again even if
/// a comparison unwinds while the element is out.