use super::*;
pub fn quick_co_sort<const N: usize, T>(list: &mut [T], mut co_lists: [&mut dyn CanSwap; N])
where
T: PartialOrd + Copy,
{
let co_lists_ptr = &mut co_lists as *mut [&mut dyn CanSwap; N];
quick_sort(0, list.len(), list, move |(a, b)| {
let co_lists = unsafe { &mut *co_lists_ptr };
for colist in co_lists.iter_mut() {
colist.ext_swap(a, b);
}
});
}
fn quick_sort<T, SWAP>(lbound: usize, ubound: usize, list: &mut [T], my_swap: SWAP)
where
T: PartialOrd + Copy,
SWAP: FnMut((usize, usize)) + Copy,
{
if (ubound - lbound) < 2 {
return;
}
let split_idx = partition(lbound, ubound, list, my_swap);
quick_sort(lbound, split_idx, list, my_swap);
quick_sort(split_idx + 1, ubound, list, my_swap);
}
fn partition<T, SWAP>(lbound: usize, ubound: usize, list: &mut [T], mut my_swap: SWAP) -> usize
where
T: PartialOrd + Copy,
SWAP: FnMut((usize, usize)),
{
let mut wall_pos = lbound + 1;
let wall_val = list[lbound];
for idx in lbound + 1..ubound {
let val = list[idx];
if val < wall_val {
list.swap(wall_pos, idx);
my_swap((wall_pos, idx));
wall_pos += 1;
}
}
list.swap(wall_pos - 1, lbound);
my_swap((wall_pos - 1, lbound));
wall_pos - 1
}
#[test]
fn partition_sanity() {
let mut test = vec![3, 1, 2, 6];
let split_idx = partition(0, test.len(), &mut test, |_| ());
assert_eq!(split_idx, 2);
assert_eq!(vec![2, 1, 3, 6], test);
let mut test = vec![-10, 2, 5, 11];
let split_idx = partition(0, test.len(), &mut test, |_| ());
assert_eq!(split_idx, 0);
assert_eq!(vec![-10, 2, 5, 11], test);
}
#[test]
fn partition_complex() {
let mut test = vec![9, -3, 100, 2, 1, -10, 15];
let pivot = partition(0, test.len(), &mut test, |_| ());
println!("{:?}", test);
println!("pivot = {}", pivot);
}
#[test]
fn quick_sort_sanity() {
let mut test = vec![9i32, 3, 100, 2, 1, 10, 15];
let mut co_test = vec![-9i32, -3, -100, -2, -1, -10, -15];
quick_co_sort(&mut test, [&mut Swappable::new(&mut co_test)]);
assert_eq!(
test.len(),
co_test.len(),
"both arrays should be equal in length"
);
assert!(
test.iter()
.zip(co_test.iter())
.all(|(&a, &b)| a.abs() == b.abs()),
"test and co_test should have the same magnitude"
);
assert!(
test.windows(2).all(|window| window[0] < window[1]),
"test should be sorted"
);
assert!(
test.iter()
.zip(co_test.iter())
.all(|(&a, &b)| a.abs() == b.abs()),
"test and co_test should have the same magnitude after sort"
);
}