pub fn quickselect<T: Ord, P: Fn(&mut [T]) -> usize>(partition: P, mut a: &mut [T], mut k: usize)
{
loop {
let p = partition(a);
if p == k {
return;
}
if p > k {
a = &mut {a}[0..p];
} else {
k = k - p - 1;
a = &mut {a}[(p+1)..];
}
}
}
#[cfg(test)]
fn sort5<T: Ord>(a: &mut [T;5])
{
let mut cswap = |i: usize, j: usize| {
if a[i] > a[j] {
a.swap(i, j)
}
};
cswap(1,2); cswap(3,4);
cswap(1,3);
cswap(0,2);
cswap(2,4);
cswap(0,3);
cswap(0,1); cswap(2,3);
cswap(1,2);
}
#[cfg(test)]
fn partition5_2<T: Ord>(a: &mut [T;5])
{
let mut cswap = |i: usize, j: usize| {
if a[i] > a[j] {
a.swap(i, j)
}
};
cswap(0,1); cswap(3,4);
cswap(0,3); cswap(1,4);
cswap(2,3);
cswap(1,2);
cswap(2,3);
}
#[cfg(test)]
fn partition5<T: Ord>(x: &mut [T;5])
{
let a = 0; let b = 1; let c = 2; let d = 3; let e = 4;
if x[c] < x[a] { x.swap(a, c); }
if x[d] < x[b] { x.swap(b, d); }
if x[d] < x[c] { x.swap(c, d); x.swap(a,b); }
if x[e] < x[b] { x.swap(b, e); }
if x[e] < x[c] {
x.swap(c, e);
if x[c] < x[a] { x.swap(a, c); }
} else if x[c] < x[b] { x.swap(b, c); }
}
fn sort3<T: Ord>(a: &mut [T;3])
{
if a[0] <= a[1] {
if a[1] <= a[2] {
} else {
if a[0] <= a[2] {
a.swap(1,2);
} else {
a.swap(0,1);
a.swap(0,2);
}
}
} else {
if a[0] <= a[2] {
a.swap(0,1);
} else {
if a[1] < a[2] {
a.swap(0,1);
a.swap(1,2);
} else {
a.swap(0,2);
}
}
}
}
pub fn repeated_step3<T: Ord>(a: &mut [T])
-> usize
{
let l = a.len();
if l < 9 {
return hoare_partition(a, l/2);
}
let mut i = 0;
let mut j = 0;
while i + 2 < a.len() {
sort3(index_fixed!(&mut a;..3));
a.swap(i+1, j);
i += 3;
j += 1;
}
let mut i = 0;
let mut m = 0;
while i + 2 < j {
sort3(index_fixed!(&mut a;..3));
a.swap(i+1, m);
i += 3;
m += 1;
}
quickselect(repeated_step3, &mut a[..m], m/2);
hoare_partition(a, m/2)
}
#[cfg(test)]
fn median_of_medians<T: Ord>(a: &mut [T])
-> usize
{
let l = a.len();
if l < 5 {
return hoare_partition(a, l/2);
}
let mut i = 0;
let mut j = 0;
while i + 4 < a.len() {
partition5(index_fixed!(&mut a;..5));
a.swap(i+2, j);
i += 5;
j += 1;
}
quickselect(median_of_medians, &mut a[0..j], j/2);
hoare_partition(a, j/2)
}
pub fn hoare_partition<T: Ord>(arr: &mut [T], pivot: usize)
-> usize
{
let p = pivot;
debug_assert!(arr.len() > 0);
debug_assert!(p < arr.len());
arr.swap(0, p);
let mut a = 1;
let mut b = arr.len() - 1;
'a: loop {
loop {
if a > b {
break 'a;
}
if arr[a] >= arr[0] {
break;
}
a += 1;
}
while arr[0] < arr[b] {
b -= 1;
}
if a >= b {
break;
}
arr.swap(a,b);
a += 1;
b -= 1;
}
a -= 1;
arr.swap(0,a);
a
}
#[cfg(test)]
mod test {
use quickcheck::TestResult;
fn is_sorted<T: Ord>(a: &[T]) -> bool {
for w in a.windows(2) {
if w[0] > w[1] {
return false;
}
}
true
}
fn is_partitioned<T: Ord>(x: &[T], p: usize) -> bool {
for i in 0..x.len() {
if i < p {
if !(x[i] <= x[p]) {
return false;
}
} else if i > p {
if !(x[i] >= x[p]) {
return true;
}
}
}
true
}
fn check_hp(x: &mut [u8], pivot: usize) -> Result<usize,String> {
let op = x[pivot];
let p = super::hoare_partition(&mut x[..], pivot);
if !(op == x[p]) {
return Err(format!("{}:{}: Check failed: {} == {}", file!(), line!(), op, x[p]));
}
if !is_partitioned(x, p) {
return Err(format!("{}:{}: not partitioned", file!(), line!()));
}
return Ok(p);
}
quickcheck! {
fn sort5(d: Vec<u8>) -> TestResult {
let mut d = d;
if d.len() < 5 {
return TestResult::discard();
}
let d = index_fixed!(&mut d;..5);
super::sort5(d);
TestResult::from_bool(is_sorted(d))
}
fn partition5(d: Vec<u8>) -> TestResult {
let mut d = d;
if d.len() < 5 {
return TestResult::discard();
}
let d = index_fixed!(&mut d;..5);
super::partition5(d);
TestResult::from_bool(is_partitioned(d, 3))
}
fn partition5_2(d: Vec<u8>) -> TestResult {
let mut d = d;
if d.len() < 5 {
return TestResult::discard();
}
let d = index_fixed!(&mut d;..5);
super::partition5_2(d);
TestResult::from_bool(is_partitioned(d, 3))
}
fn sort3(d: Vec<u8>) -> TestResult {
let mut d = d;
if d.len() < 3 {
return TestResult::discard();
}
let d = index_fixed!(&mut d;..3);
super::sort3(d);
if !is_sorted(d) {
println!("{}:{}: {:?}", file!(), line!(), d);
}
TestResult::from_bool(is_sorted(d))
}
fn qs_median_of_medians(d: Vec<u8>, po: usize) -> TestResult {
let mut d = d;
if d.len() == 0 {
return TestResult::discard();
}
if po >= d.len() {
return TestResult::discard();
}
super::quickselect(super::median_of_medians, &mut d[..], po);
TestResult::from_bool(is_partitioned(&mut d[..], po))
}
fn qs_repeated_step3(d: Vec<u8>, po: usize) -> TestResult {
let mut d = d;
if d.len() == 0 {
return TestResult::discard();
}
if po >= d.len() {
return TestResult::discard();
}
super::quickselect(super::repeated_step3, &mut d[..], po);
TestResult::from_bool(is_partitioned(&mut d[..], po))
}
fn hoare_partition_qc(data: Vec<u8>, pos: usize) -> TestResult {
let mut d = data;
if d.len() == 0 {
return TestResult::discard();
}
if pos >= d.len() {
return TestResult::discard();
}
TestResult::from_bool(check_hp(&mut d[..], pos).is_ok())
}
}
}
#[cfg(all(test, feature = "nightly"))]
mod bench {
extern crate test;
extern crate rand;
use self::rand::Rng;
#[bench]
fn partition5(b: &mut test::Bencher) {
let mut rng = rand::thread_rng();
let mut d = [0u8; 5];
b.iter(|| {
rng.fill_bytes(&mut d);
super::partition5(&mut d);
})
}
#[bench]
fn partition5_2(b: &mut test::Bencher) {
let mut rng = rand::thread_rng();
let mut d = [0u8; 5];
b.iter(|| {
rng.fill_bytes(&mut d);
super::partition5_2(&mut d);
})
}
const BENCH_LEN: usize = 1024 * 512;
#[bench]
fn median_of_medians_big(b: &mut test::Bencher) {
let mut rng = rand::thread_rng();
let mut d = vec![0u8; BENCH_LEN];
b.iter(|| {
rng.fill_bytes(&mut d);
let p = rng.gen::<usize>() % d.len();
super::quickselect(super::median_of_medians, &mut d[..], p)
})
}
#[bench]
fn repeated_step3_big(b: &mut test::Bencher) {
let mut rng = rand::thread_rng();
let mut d = vec![0u8; BENCH_LEN];
b.iter(|| {
rng.fill_bytes(&mut d);
let p = rng.gen::<usize>() % d.len();
super::quickselect(super::repeated_step3, &mut d[..], p)
})
}
}