Rollup merge of #107522 - Sp00ph:introselect, r=Amanieu
Add Median of Medians fallback to introselect Fixes #102451. This PR is a follow up to #106997. It adds a Fast Deterministic Selection implementation as a fallback to the introselect algorithm used by `select_nth_unstable`. This allows it to guarantee O(n) worst case running time, while maintaining good performance in all cases. This would fix #102451, which was opened because the `select_nth_unstable` docs falsely claimed that it had O(n) worst case performance, even though it was actually quadratic in the worst case. #106997 improved the worst case complexity to O(n log n) by using heapsort as a fallback, and this PR further improves it to O(n) (this would also make #106933 unnecessary). It also improves the actual runtime if the fallback gets called: Using a pathological input of size `1 << 19` (see the playground link in #102451), calculating the median is roughly 3x faster using fast deterministic selection as a fallback than it is using heapsort. The downside to this is less code reuse between the sorting and selection algorithms, but I don't think it's that bad. The additional algorithms are ~250 LOC with no `unsafe` blocks (I tried using unsafe to avoid bounds checks but it didn't noticeably improve the performance). I also let it fuzz for a while against the current `select_nth_unstable` implementation to ensure correctness, and it seems to still fulfill all the necessary postconditions. cc `@scottmcm` who reviewed #106997
This commit is contained in:
@@ -42,6 +42,7 @@ mod index;
|
||||
mod iter;
|
||||
mod raw;
|
||||
mod rotate;
|
||||
mod select;
|
||||
mod specialize;
|
||||
|
||||
#[unstable(feature = "str_internals", issue = "none")]
|
||||
@@ -3034,7 +3035,7 @@ impl<T> [T] {
|
||||
where
|
||||
T: Ord,
|
||||
{
|
||||
sort::partition_at_index(self, index, T::lt)
|
||||
select::partition_at_index(self, index, T::lt)
|
||||
}
|
||||
|
||||
/// Reorder the slice with a comparator function such that the element at `index` is at its
|
||||
@@ -3089,7 +3090,7 @@ impl<T> [T] {
|
||||
where
|
||||
F: FnMut(&T, &T) -> Ordering,
|
||||
{
|
||||
sort::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less)
|
||||
select::partition_at_index(self, index, |a: &T, b: &T| compare(a, b) == Less)
|
||||
}
|
||||
|
||||
/// Reorder the slice with a key extraction function such that the element at `index` is at its
|
||||
@@ -3145,7 +3146,7 @@ impl<T> [T] {
|
||||
F: FnMut(&T) -> K,
|
||||
K: Ord,
|
||||
{
|
||||
sort::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b)))
|
||||
select::partition_at_index(self, index, |a: &T, b: &T| f(a).lt(&f(b)))
|
||||
}
|
||||
|
||||
/// Moves all consecutive repeated elements to the end of the slice according to the
|
||||
|
||||
Reference in New Issue
Block a user