Skip to content

Commit e6b7b02

Browse files
committed
Implement skewed pivot sampling.
1 parent 6be4cfd commit e6b7b02

File tree

1 file changed

+35
-13
lines changed

1 file changed

+35
-13
lines changed

src/sort.rs

Lines changed: 35 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,21 +48,21 @@ where
4848
S: DataMut,
4949
S2: Data<Elem = usize>;
5050

51-
/// Partitions the array in increasing order based on the values initially located at `0` and
52-
/// `n - 1` where `n` is the number of elements in the array and returns the new indexes of the
53-
/// values.
51+
/// Partitions the array in increasing order at two skewed pivot values as 1st and 3rd element
52+
/// of a sorted sample of 5 equally spaced elements around the center and returns their indexes.
53+
/// For arrays of less than 42 elements the outermost elements serve as sample for pivot values.
5454
///
55-
/// The elements are rearranged in such a way that the values initially located at `0` and
56-
/// `n - 1` are moved to the position it would be in an array sorted in increasing order. The
57-
/// return values are the new indexes of the values after rearrangement. All elements less than
58-
/// the values are moved to their left and all elements equal or greater than the values are
59-
/// moved to their right. The ordering of the elements in the three partitions is undefined.
55+
/// The elements are rearranged in such a way that the two pivot values are moved to the indexes
56+
/// they would be in an array sorted in increasing order. The return values are the new indexes
57+
/// of the values after rearrangement. All elements less than the values are moved to their left
58+
/// and all elements equal or greater than the values are moved to their right. The ordering of
59+
/// the elements in the three partitions is undefined.
6060
///
6161
/// The array is shuffled **in place**, no copy of the array is allocated.
6262
///
63-
/// This method implements the partitioning scheme of [Yaroslavskiy-Bentley-Bloch Quicksort].
63+
/// This method performs [dual-pivot partitioning] with skewed pivot sampling.
6464
///
65-
/// [Yaroslavskiy-Bentley-Bloch Quicksort]: https://api.semanticscholar.org/CorpusID:51871084
65+
/// [dual-pivot partitioning]: https://www.wild-inter.net/publications/wild-2018b.pdf
6666
///
6767
/// # Example
6868
///
@@ -151,11 +151,33 @@ where
151151
A: Ord + Clone,
152152
S: DataMut,
153153
{
154-
// Sort `lowermost` and `uppermost` elements and use them as dual pivot.
155154
let lowermost = 0;
156155
let uppermost = self.len() - 1;
157-
if self[lowermost] > self[uppermost] {
158-
self.swap(lowermost, uppermost);
156+
if self.len() < 42 {
157+
// Sort outermost elements and use them as pivots.
158+
if self[lowermost] > self[uppermost] {
159+
self.swap(lowermost, uppermost);
160+
}
161+
} else {
162+
// Sample indexes of 5 evenly spaced elements around the center element.
163+
let mut samples = [0; 5];
164+
// Assume array of at least 7 elements.
165+
let seventh = self.len() / (samples.len() + 2);
166+
samples[2] = self.len() / 2;
167+
samples[1] = samples[2] - seventh;
168+
samples[0] = samples[1] - seventh;
169+
samples[3] = samples[2] + seventh;
170+
samples[4] = samples[3] + seventh;
171+
// Use insertion sort for sample elements by looking up their indexes.
172+
for mut index in 1..samples.len() {
173+
while index > 0 && self[samples[index - 1]] > self[samples[index]] {
174+
self.swap(samples[index - 1], samples[index]);
175+
index -= 1;
176+
}
177+
}
178+
// Use 1st and 3rd element of sorted sample as skewed pivots.
179+
self.swap(lowermost, samples[0]);
180+
self.swap(uppermost, samples[2]);
159181
}
160182
// Increasing running and partition index starting after lower pivot.
161183
let mut index = lowermost + 1;

0 commit comments

Comments
 (0)