@@ -831,6 +831,15 @@ fn partition_at_index_loop<'a, T, F>(
831831) where
832832 F : FnMut ( & T , & T ) -> bool ,
833833{
834+ // Limit the amount of iterations and fall back to heapsort, similarly to `slice::sort_unstable`.
835+ // This lowers the worst case running time from O(n^2) to O(n log n).
836+ // FIXME: Investigate whether it would be better to use something like Median of Medians
837+ // or Fast Deterministic Selection to guarantee O(n) worst case.
838+ let mut limit = usize:: BITS - v. len ( ) . leading_zeros ( ) ;
839+
840+ // True if the last partitioning was reasonably balanced.
841+ let mut was_balanced = true ;
842+
834843 loop {
835844 // For slices of up to this length it's probably faster to simply sort them.
836845 const MAX_INSERTION : usize = 10 ;
@@ -839,6 +848,18 @@ fn partition_at_index_loop<'a, T, F>(
839848 return ;
840849 }
841850
851+ if limit == 0 {
852+ heapsort ( v, is_less) ;
853+ return ;
854+ }
855+
856+ // If the last partitioning was imbalanced, try breaking patterns in the slice by shuffling
857+ // some elements around. Hopefully we'll choose a better pivot this time.
858+ if !was_balanced {
859+ break_patterns ( v) ;
860+ limit -= 1 ;
861+ }
862+
842863 // Choose a pivot
843864 let ( pivot, _) = choose_pivot ( v, is_less) ;
844865
@@ -863,6 +884,7 @@ fn partition_at_index_loop<'a, T, F>(
863884 }
864885
865886 let ( mid, _) = partition ( v, pivot, is_less) ;
887+ was_balanced = cmp:: min ( mid, v. len ( ) - mid) >= v. len ( ) / 8 ;
866888
867889 // Split the slice into `left`, `pivot`, and `right`.
868890 let ( left, right) = v. split_at_mut ( mid) ;
0 commit comments