use crate::{
heap_sort::heap_sort,
insertion_sort::insertion_sort_shift_left,
insertion_sort::partial_insertion_sort,
maybe_grow,
partition::{break_patterns, choose_pivot, partition, partition_equal},
};
use core::{cmp, mem};
use ndarray::{ArrayViewMut1, Axis, IndexLonger};
pub fn quick_sort<T, F>(v: ArrayViewMut1<'_, T>, mut is_less: F)
where
F: FnMut(&T, &T) -> bool,
{
if mem::size_of::<T>() == 0 {
return;
}
let limit = usize::BITS - v.len().leading_zeros();
recurse(v, &mut is_less, None, limit);
}
fn recurse<'a, T, F>(
mut v: ArrayViewMut1<'a, T>,
is_less: &mut F,
mut pred: Option<&'a T>,
mut limit: u32,
) where
F: FnMut(&T, &T) -> bool,
{
const MAX_INSERTION: usize = 20;
let mut was_balanced = true;
let mut was_partitioned = true;
loop {
let len = v.len();
if len <= MAX_INSERTION {
if len >= 2 {
insertion_sort_shift_left(v, 1, is_less);
}
return;
}
if limit == 0 {
heap_sort(v, is_less);
return;
}
if !was_balanced {
break_patterns(v.view_mut());
limit -= 1;
}
let (pivot, likely_sorted) = choose_pivot(v.view_mut(), is_less);
if was_balanced && was_partitioned && likely_sorted {
if partial_insertion_sort(v.view_mut(), is_less) {
return;
}
}
if let Some(p) = pred {
if !is_less(p, &v[pivot]) {
let mid = partition_equal(v.view_mut(), pivot, is_less);
let (_, new_v) = v.split_at(Axis(0), mid);
v = new_v;
continue;
}
}
let (mid, was_p) = partition(v.view_mut(), pivot, is_less);
was_balanced = cmp::min(mid, len - mid) >= len / 8;
was_partitioned = was_p;
let (left, right) = v.split_at(Axis(0), mid);
let (pivot, right) = right.split_at(Axis(0), 1);
let pivot = pivot.index(0);
if left.len() < right.len() {
maybe_grow(|| recurse(left, is_less, pred, limit));
v = right;
pred = Some(pivot);
} else {
maybe_grow(|| recurse(right, is_less, Some(pivot), limit));
v = left;
}
}
}
#[cfg(feature = "std")]
#[cfg(test)]
mod test {
use super::quick_sort;
use ndarray::Array1;
use quickcheck_macros::quickcheck;
#[quickcheck]
fn sorted(xs: Vec<u32>) {
let mut sorted = xs.clone();
sorted.sort_unstable();
let sorted = Array1::from_vec(sorted);
let mut array = Array1::from_vec(xs);
quick_sort(array.view_mut(), &mut u32::lt);
assert_eq!(array, sorted);
}
}