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
use crate::{here,Mutsort,Vecops};
impl<T> Mutsort<T> for &mut[T] {
/// sort two slice items if they are out of ascending order
fn mutsorttwo(self, i0: usize, i1:usize) -> bool where T: PartialOrd {
if self[i0] > self[i1] { self.swap(i0,i1); true }
else { false }
}
/// sort three slice items if they are out of ascending order
fn mutsortthree(self, i0: usize, i1:usize, i2:usize) where T: PartialOrd {
self.mutsorttwo(i0,i1);
if self.mutsorttwo(i1,i2) { self.mutsorttwo(i0,i1); };
}
/// N recursive hash sort.
/// Sorts mutable first argument (slice) in place
/// Requires [min,max], the data range, that must enclose all its values.
/// The range is often known in advance. If not, it can be obtained with `minmaxt()`.
fn muthashsort(self, min:f64, max:f64) where T: PartialOrd+Copy, f64:From<T> {
if min >= max { panic!("{} data range must be min < max",here!()); };
self.muthashsortslice(0,self.len(),min,max);
}
/// Does the work for `muthashsort`
///
fn muthashsortslice(self, i:usize, n:usize, min:f64, max:f64)
where T: PartialOrd+Copy, f64:From<T> {
// Recursion termination conditions
match n {
0|1 => { return; }, // no sorting needed
2 => { self.mutsorttwo(i,i+1); return; },
3 => { self.mutsortthree(i,i+1,i+2); return; },
_ => ()
};
// hash is a precomputed factor, s.t. ((x-min)*hash).floor() subscripts will be in [0,n]
// this is then reduced to [0,n-1]
let hash = n as f64 / (max-min);
let mut buckets:Vec<Vec<T>> = vec![Vec::new();n];
// group data items into buckets, subscripted by the data hash values
for &xi in self.iter().skip(i).take(n) {
let mut hashsub = (hash*(f64::from(xi)-min)).floor() as usize;
if hashsub == n { hashsub -= 1; };
buckets[hashsub].push(xi);
};
// isub to point at the current place in the self data
let mut isub = i;
// sort and copy the buckets into the self
for bucket in buckets.iter() {
let blen = bucket.len(); // size of the current bucket
// up to three items in a bucket can be sorted immediately
// println!("muthashsortslice bucket start: {} items: {}",isub,blen);
match blen {
0 => continue, // empty bucket
1 => { self[isub] = bucket[0]; isub += 1; }, // copy the item to the main index
2 => {
self[isub] = bucket[0]; self[isub+1] = bucket[1];
self.mutsorttwo(isub,isub+1);
isub += 2;
},
3 => {
self[isub] = bucket[0]; self[isub+1] = bucket[1]; self[isub+2] = bucket[2];
self.mutsortthree(isub,isub+1,isub+2);
isub += 3;
},
x if x == n => {
// this bucket alone is populated,
// items in it are most likely all equal
// we need not copy bucket into self, as no grouping took place
let mx = self.minmax_slice(isub, blen);
if mx.min < mx.max { // not all the same
self.mutsorttwo(isub,mx.minindex); // swap min to the front
self.mutsorttwo(mx.maxindex,isub+n-1); // and swap max to the end
// recurse to sort the rest, within the new reduced range
self.muthashsortslice(isub+1,blen-2,f64::from(mx.min),f64::from(mx.max));
};
return; // all items in this single bucket were equal, or are now sorted
},
_ => {
// copy to self the grouped but as yet unsorted items from bucket
let isubprev = isub;
for &item in bucket { self[isub] = item; isub += 1; };
// isub-1 now points at the last copied item
let mx = self.minmax_slice(isubprev, blen);
if mx.min < mx.max {
self.mutsorttwo(isubprev,mx.minindex); // swap min to the front
self.mutsorttwo(mx.maxindex,isub-1); // and swap max to the end
// recurse to sort the rest in between, with reduced data range
self.muthashsortslice(isubprev+1,blen-2,f64::from(mx.min),f64::from(mx.max));
};
} // items in this bucket were equal or are now sorted
} // end of match (this bucket) but there may be more
} // end of for (all buckets)
}
}