Reputation: 43
I have a quick_sort code (С++) that looks like this
template< typename BidirectionalIterator, typename Compare >
BidirectionalIterator quick_sort_partition( BidirectionalIterator left, BidirectionalIterator right, Compare cmp ) {
BidirectionalIterator q = left - 1;
std::mt19937 gen(time(0));
std::uniform_int_distribution<int> uid(0, right - left - 1);
int pivot_1 = uid(gen) ;
BidirectionalIterator randomNum = pivot_1 + left;
std::iter_swap( randomNum, right );
bool index = 0;
for (BidirectionalIterator i = left; i < right; i++){
if (*i < *right){
++q;
std::iter_swap( q, i );
}
if (*i == *right){
index = 1 - index;
if(index){
++q;
std::iter_swap( q, i );
}
}
}
++q;
std::iter_swap( q, right );
return q;
}
template< typename BidirectionalIterator, typename Compare >
void quick_sort( BidirectionalIterator first, BidirectionalIterator last, Compare cmp ) {
if (first < last){
BidirectionalIterator q = quick_sort_partition(first, last, cmp);
quick_sort(first, q - 1, cmp);
quick_sort(q + 1, last, cmp);
}
}
but he is slower(more 6 times) than std::sort on big tests.
Any ideas why?
How to optimize my code for good job?
Upvotes: 4
Views: 403
Reputation: 180266
Your QuickSort implementation is pretty vanilla. It does use random pivot selection, which ensures that there are no "killer" inputs that cause performance degredation, so that's better than the absolute basic QuickSort.
There are a number of optimizations that might be used, among them:
It is typical for "Quick Sort" to in fact be implemented as a hybrid sort that falls back to (say) Insertion Sort for partitions smaller than some fixed threshold. Once you get to small partitions, the overhead of Quick Sort tends to overcome its asymptotic complexity advantages.
Maximum recursion depth can be minimized and function call overhead can be reduced by switching to a hybrid recursive / iterative approach, wherein upon each partitioning, the smaller sub-array is sorted recursively, but the code just loops to sort the larger one.
When partitioning, you can reduce the number of swaps performed by finding pairs of elements for which a swap puts both in the correct sub-partition, and swapping those, instead of alternating between swapping into one sub-partition and swapping into the other.
It would probably help to come up with a way to reuse the same random number source throughout the sort, instead of instantiating a new one upon every partitioning.
Upvotes: 4