Add heapsort fallback in select_nth_unstable
This commit is contained in:
parent
38a76f3322
commit
273c6c3913
@ -831,6 +831,15 @@ fn partition_at_index_loop<'a, T, F>(
|
|||||||
) where
|
) where
|
||||||
F: FnMut(&T, &T) -> bool,
|
F: FnMut(&T, &T) -> bool,
|
||||||
{
|
{
|
||||||
|
// Limit the amount of iterations and fall back to heapsort, similarly to `slice::sort_unstable`.
|
||||||
|
// This lowers the worst case running time from O(n^2) to O(n log n).
|
||||||
|
// FIXME: Investigate whether it would be better to use something like Median of Medians
|
||||||
|
// or Fast Deterministic Selection to guarantee O(n) worst case.
|
||||||
|
let mut limit = usize::BITS - v.len().leading_zeros();
|
||||||
|
|
||||||
|
// True if the last partitioning was reasonably balanced.
|
||||||
|
let mut was_balanced = true;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// For slices of up to this length it's probably faster to simply sort them.
|
// For slices of up to this length it's probably faster to simply sort them.
|
||||||
const MAX_INSERTION: usize = 10;
|
const MAX_INSERTION: usize = 10;
|
||||||
@ -839,6 +848,18 @@ fn partition_at_index_loop<'a, T, F>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if limit == 0 {
|
||||||
|
heapsort(v, is_less);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the last partitioning was imbalanced, try breaking patterns in the slice by shuffling
|
||||||
|
// some elements around. Hopefully we'll choose a better pivot this time.
|
||||||
|
if !was_balanced {
|
||||||
|
break_patterns(v);
|
||||||
|
limit -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
// Choose a pivot
|
// Choose a pivot
|
||||||
let (pivot, _) = choose_pivot(v, is_less);
|
let (pivot, _) = choose_pivot(v, is_less);
|
||||||
|
|
||||||
@ -863,6 +884,7 @@ fn partition_at_index_loop<'a, T, F>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (mid, _) = partition(v, pivot, is_less);
|
let (mid, _) = partition(v, pivot, is_less);
|
||||||
|
was_balanced = cmp::min(mid, v.len() - mid) >= v.len() / 8;
|
||||||
|
|
||||||
// Split the slice into `left`, `pivot`, and `right`.
|
// Split the slice into `left`, `pivot`, and `right`.
|
||||||
let (left, right) = v.split_at_mut(mid);
|
let (left, right) = v.split_at_mut(mid);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user