2020 /// No other assumptions should be made on the ordering of the
2121 /// elements after this computation.
2222 ///
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].
2524 ///
2625 /// [Sesquickselect]: https://www.wild-inter.net/publications/martinez-nebel-wild-2019.pdf
2726 ///
4847 S : DataMut ,
4948 S2 : Data < Elem = usize > ;
5049
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-
5950 /// Partitions the array in increasing order based on the value initially
6051 /// located at `pivot_index` and returns the new index of the value.
6152 ///
@@ -182,6 +173,8 @@ where
182173 } else {
183174 // Adapt pivot sampling to relative sought rank and switch from dual-pivot to
184175 // single-pivot partitioning for extreme sought ranks.
176+ let mut sample = [ 0 ; 5 ] ;
177+ sample_mut ( self , & mut sample) ;
185178 let sought_rank = i as f64 / n as f64 ;
186179 if ( 0.036 ..=0.964 ) . contains ( & sought_rank) {
187180 let ( lower_index, upper_index) = if sought_rank <= 0.5 {
@@ -197,7 +190,6 @@ where
197190 ( 3 , 4 ) // (3, 0, 0)
198191 }
199192 } ;
200- let sample = self . sample_mut ( ) ;
201193 let ( lower_index, upper_index) =
202194 self . dual_partition_mut ( sample[ lower_index] , sample[ upper_index] ) ;
203195 if i < lower_index {
@@ -215,7 +207,6 @@ where
215207 . get_from_sorted_mut ( i - ( upper_index + 1 ) )
216208 }
217209 } else {
218- let sample = self . sample_mut ( ) ;
219210 let pivot_index = if sought_rank <= 0.5 {
220211 0 // (0, 4)
221212 } else {
@@ -248,29 +239,6 @@ where
248239 get_many_from_sorted_mut_unchecked ( self , & deduped_indexes)
249240 }
250241
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-
274242 fn partition_mut ( & mut self , pivot_index : usize ) -> usize
275243 where
276244 A : Ord + Clone ,
@@ -434,7 +402,8 @@ fn _get_many_from_sorted_mut_unchecked<A>(
434402
435403 // Since there is no single sought rank to adapt pivot sampling to, the recommended skewed pivot
436404 // 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) ;
438407 let ( lower_index, upper_index) = ( sample[ 0 ] , sample[ 2 ] ) ; // (0, 1, 2)
439408
440409 // 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>(
506475 upper_values,
507476 ) ;
508477}
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