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
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.
///
/// 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`]: 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"]);
/// ```
/// 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.