use crate::key::SortableKey;
#[inline]
pub fn insertion_sort<T: SortableKey>(slice: &mut [T]) {
for i in 1..slice.len() {
let key_i = slice[i].to_radix_key();
let mut j = i;
while j > 0 && slice[j - 1].to_radix_key() > key_i {
slice.swap(j, j - 1);
j -= 1;
}
}
}
#[inline]
pub fn hoare_partition<T: SortableKey>(slice: &mut [T], pivot_key: T::Key) -> usize {
let mut left = 0;
let mut right = slice.len();
loop {
while left < right && slice[left].to_radix_key() < pivot_key {
left += 1;
}
while left < right && slice[right - 1].to_radix_key() >= pivot_key {
right -= 1;
}
if left >= right {
return left;
}
slice.swap(left, right - 1);
left += 1;
right -= 1;
}
}
#[inline]
pub fn median_of_three_key<T: SortableKey>(slice: &[T]) -> T::Key {
let len = slice.len();
let a = slice[0].to_radix_key();
let b = slice[len / 2].to_radix_key();
let c = slice[len - 1].to_radix_key();
if a <= b {
if b <= c {
b
} else if a <= c {
c
} else {
a
}
} else if a <= c {
a
} else if b <= c {
c
} else {
b
}
}
pub fn quicksort<T: SortableKey>(slice: &mut [T]) {
quicksort_impl(slice, 2 * log2_usize(slice.len()));
}
fn quicksort_impl<T: SortableKey>(slice: &mut [T], depth_limit: usize) {
if slice.len() <= 16 {
insertion_sort(slice);
return;
}
if depth_limit == 0 {
insertion_sort(slice);
return;
}
let pivot_key = median_of_three_key(slice);
let mid = hoare_partition(slice, pivot_key);
if mid == 0 || mid == slice.len() {
insertion_sort(slice);
return;
}
let (left, right) = slice.split_at_mut(mid);
quicksort_impl(left, depth_limit - 1);
quicksort_impl(right, depth_limit - 1);
}
#[inline]
fn log2_usize(n: usize) -> usize {
if n == 0 {
return 0;
}
usize::BITS as usize - 1 - n.leading_zeros() as usize
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn insertion_sort_basic() {
let mut data = vec![5i32, 3, 8, 1, 9, 2, 7, 4, 6];
insertion_sort(&mut data);
assert_eq!(data, vec![1, 2, 3, 4, 5, 6, 7, 8, 9]);
}
#[test]
fn quicksort_basic() {
let mut data = vec![
5u32, 3, 8, 1, 9, 2, 7, 4, 6, 10, 15, 12, 11, 14, 13, 16, 17, 18,
];
quicksort(&mut data);
let mut expected = data.clone();
expected.sort();
assert_eq!(data, expected);
}
#[test]
fn quicksort_all_equal() {
let mut data = vec![42u32; 100];
quicksort(&mut data);
assert!(data.iter().all(|&x| x == 42));
}
#[test]
fn quicksort_signed() {
let mut data = vec![3i32, -1, 4, -1, 5, -9, 2, -6, 5, 3];
quicksort(&mut data);
let mut expected = data.clone();
expected.sort();
assert_eq!(data, expected);
}
}