20
20
/// No other assumptions should be made on the ordering of the
21
21
/// elements after this computation.
22
22
///
23
- /// This method performs a variant of [Sesquickselect] with pivot samples of 5 equally spaced
24
- /// elements around the center.
23
+ /// This method performs [Sesquickselect].
25
24
///
26
25
/// [Sesquickselect]: https://www.wild-inter.net/publications/martinez-nebel-wild-2019.pdf
27
26
///
48
47
S : DataMut ,
49
48
S2 : Data < Elem = usize > ;
50
49
51
- /// Sorts a sample of 5 equally spaced elements around the center and returns their indexes.
52
- ///
53
- /// **Panics** for arrays of less than 7 elements.
54
- fn sample_mut ( & mut self ) -> [ usize ; 5 ]
55
- where
56
- A : Ord + Clone ,
57
- S : DataMut ;
58
-
59
50
/// Partitions the array in increasing order based on the value initially
60
51
/// located at `pivot_index` and returns the new index of the value.
61
52
///
@@ -182,6 +173,8 @@ where
182
173
} else {
183
174
// Adapt pivot sampling to relative sought rank and switch from dual-pivot to
184
175
// single-pivot partitioning for extreme sought ranks.
176
+ let mut sample = [ 0 ; 5 ] ;
177
+ sample_mut ( self , & mut sample) ;
185
178
let sought_rank = i as f64 / n as f64 ;
186
179
if ( 0.036 ..=0.964 ) . contains ( & sought_rank) {
187
180
let ( lower_index, upper_index) = if sought_rank <= 0.5 {
@@ -197,7 +190,6 @@ where
197
190
( 3 , 4 ) // (3, 0, 0)
198
191
}
199
192
} ;
200
- let sample = self . sample_mut ( ) ;
201
193
let ( lower_index, upper_index) =
202
194
self . dual_partition_mut ( sample[ lower_index] , sample[ upper_index] ) ;
203
195
if i < lower_index {
@@ -215,7 +207,6 @@ where
215
207
. get_from_sorted_mut ( i - ( upper_index + 1 ) )
216
208
}
217
209
} else {
218
- let sample = self . sample_mut ( ) ;
219
210
let pivot_index = if sought_rank <= 0.5 {
220
211
0 // (0, 4)
221
212
} else {
@@ -248,29 +239,6 @@ where
248
239
get_many_from_sorted_mut_unchecked ( self , & deduped_indexes)
249
240
}
250
241
251
- fn sample_mut ( & mut self ) -> [ usize ; 5 ]
252
- where
253
- A : Ord + Clone ,
254
- S : DataMut ,
255
- {
256
- // Space between sample indexes.
257
- let space = self . len ( ) / 7 ;
258
- assert ! ( space > 0 , "Cannot sample array of less then 7 elements" ) ;
259
- // Initialize sample indexes with their lowermost index.
260
- let mut samples = [ self . len ( ) / 2 - 2 * space; 5 ] ;
261
- // Equally space sample indexes and sort by their values by looking up their indexes.
262
- for mut index in 1 ..samples. len ( ) {
263
- // Equally space sample indexes based on their lowermost index.
264
- samples[ index] += index * space;
265
- // Insertion sort looking up only the already equally spaced sample indexes.
266
- while index > 0 && self [ samples[ index - 1 ] ] > self [ samples[ index] ] {
267
- self . swap ( samples[ index - 1 ] , samples[ index] ) ;
268
- index -= 1 ;
269
- }
270
- }
271
- samples
272
- }
273
-
274
242
fn partition_mut ( & mut self , pivot_index : usize ) -> usize
275
243
where
276
244
A : Ord + Clone ,
@@ -434,7 +402,8 @@ fn _get_many_from_sorted_mut_unchecked<A>(
434
402
435
403
// Since there is no single sought rank to adapt pivot sampling to, the recommended skewed pivot
436
404
// sampling of dual-pivot Quicksort is used.
437
- let sample = array. sample_mut ( ) ;
405
+ let mut sample = [ 0 ; 5 ] ;
406
+ sample_mut ( & mut array, & mut sample) ;
438
407
let ( lower_index, upper_index) = ( sample[ 0 ] , sample[ 2 ] ) ; // (0, 1, 2)
439
408
440
409
// We partition the array with respect to the two pivot values. The pivot values move to the new
@@ -506,3 +475,29 @@ fn _get_many_from_sorted_mut_unchecked<A>(
506
475
upper_values,
507
476
) ;
508
477
}
478
+
479
+ /// Equally space `sample` indexes around the center of `array` and sort them by their values.
480
+ ///
481
+ /// `sample` content is ignored but its length defines the sample size and the sample space divider.
482
+ ///
483
+ /// Assumes arrays of at least `sample.len() + 2` elements.
484
+ pub ( crate ) fn sample_mut < A , S > ( array : & mut ArrayBase < S , Ix1 > , sample : & mut [ usize ] )
485
+ where
486
+ A : Ord + Clone ,
487
+ S : DataMut < Elem = A > ,
488
+ {
489
+ // Space between sample indexes.
490
+ let space = array. len ( ) / ( sample. len ( ) + 2 ) ;
491
+ // Lowermost sample index.
492
+ let lowermost = array. len ( ) / 2 - ( sample. len ( ) / 2 ) * space;
493
+ // Equally space sample indexes and sort them by their values by looking up their indexes.
494
+ for mut index in 1 ..sample. len ( ) {
495
+ // Equally space sample indexes based on their lowermost index.
496
+ sample[ index] = lowermost + index * space;
497
+ // Insertion sort looking up only the already equally spaced sample indexes.
498
+ while index > 0 && array[ sample[ index - 1 ] ] > array[ sample[ index] ] {
499
+ array. swap ( sample[ index - 1 ] , sample[ index] ) ;
500
+ index -= 1 ;
501
+ }
502
+ }
503
+ }
0 commit comments