5

As far as I know (despite some variations which provide empirical average-case improvements) quick-sort is worst case $O(n^2)$ with the original Hoare partition scheme having a particularly bad behavior for already sorted lists, reverse-sorted, repeated element lists.

On the other hand a B-Tree has $O(\log n)$ insertions, meaning worst-case $O(n\log n)$ to process an array of $n$ elements. Also an easy optimization to memoize the memory-address of the lowest and highest nodes (would make it possible to process sorted / reverse-sorted / repeated-element lists in $O(n)$).

While there are more favored sorting algorithms than quicksort now (e.g. timsort) what originally favored its use? Is it the susceptibility to parallelization (also in place swaps, lower memory complexity)? Otherwise why not just use a B-tree?

Raphael
  • 72,336
  • 29
  • 179
  • 389
user3467349
  • 387
  • 2
  • 12
  • 1
    Quicksort's worst case rarely happens. Its average performance complexity is O(nlog(n)). Also it has a "best case" of O(n) in the "three-way partition and equal keys" way. – Alaa M. Nov 27 '16 at 14:08
  • I don't see how quick-sort is ever $O(n)$ do you have a reference (the wikipedia article makes the claim but it does not)? – user3467349 Nov 27 '16 at 14:14
  • Besides wikipedia there's another claim here: https://www.toptal.com/developers/sorting-algorithms/quick-sort-3-way . Read at the bottom "Adaptive: O(n) time when O(1) unique keys" – Alaa M. Nov 27 '16 at 14:17
  • That's also not a reference with any kind of analysis. By wikipedia I'm guessing you mean https://en.wikipedia.org/wiki/Multi-key_quicksort and not the best-case analysis mentioned here: https://en.wikipedia.org/wiki/Quicksort#Best-case_analysis (which is clearly $O(nlog(n))$ I haven't read about the multi-key quicksort (but note that it's a hybrid and developed much later) so I'll have to do that. – user3467349 Nov 27 '16 at 14:24
  • In wikipedia I mean in the infobox on the right in Quicksort. But I don't have any proof of it. – Alaa M. Nov 27 '16 at 14:27
  • Yes, I read the info-box as well, but if you look at the section at #Best-case_analysis the result is $O(nlog(n))$ (And it seems obvious that you couldn't perform better without altering the algorithm). Why the the info-box has $O(n)$ I don't know: there is probably a quick-sort optimization for which that is true -- but no section of the article corresponds to that figure. – user3467349 Nov 27 '16 at 14:30
  • 1
    Apple's implementation looks for one sorted run (ascending or descending) at the start and one at the end of the array, which turns many practical use cases into O (n). For example, sorting an array that is already sorted in ascending or descending order, or the concatenation of two such array. Or a sorted array with O (n / log n) random elements added at the end. – gnasher729 Nov 27 '16 at 14:40
  • 6
    Read: http://cs.stackexchange.com/questions/3/why-is-quicksort-better-than-other-sorting-algorithms-in-practice – Alaa M. Nov 27 '16 at 15:28
  • 1
    (Choice of partition scheme doesn't decide worst case performance: choice of pivot value does.) – greybeard Nov 27 '16 at 15:52
  • @AlaaM. I have read this, but that answer doesn't address B-tree's at all. I suspect Node creation for a B-Tree tends to be more expensive than sort time but that's not an interesting argument. In contrast this paper http://www.cs.princeton.edu/~rs/strings/paper.pdf (Bentley and Sedgewick) states that B-Tree's are an isomorphism of quicksort (though it doesn't provide the a proof) but there is certainly a substantial answer to this question. Quicksort performance is usually not worst-case isn't something I needed someone to tell me on stackexchange. – user3467349 Nov 28 '16 at 14:36
  • @greybeard Both, actually. – Raphael Dec 04 '16 at 02:07
  • @user3467349 The answer lies in the constant factors: constructing tree data structures in memory is a lot more expensive than rearranging values in an array. – Raphael Dec 04 '16 at 02:12
  • @Raphael: Both, actually - discussing order of growth of quicksort execution time? Regarding partition schemes, I'd love to know an officious name for the "swapless" one presented by Moder for code review. – greybeard Dec 04 '16 at 07:47
  • @greybeard The worst cases differ between different partitioning methods. (About that other thing, you may post your own [tag:reference-request]. But since the algorithms seems to be faulty, maybe it's a moot point?) – Raphael Dec 04 '16 at 10:57
  • @Raphael While I'd still like an officious name for the "Partition without Exchange" scheme, C.A.R. Hoare described it in his article about quicksort in The Computer Journal (1962) 5 (1): 10-16, in a paragraph titled thus. – greybeard Dec 04 '16 at 13:53

2 Answers2

3

A B-tree has one significant disadvantage on the fastest deep cache machines, it depends on pointers. So as the size grows each access have a greater and greater risk of causing a cache-miss/TLB-miss. Effectively getting a K value of z*x, x=sum(cache/TLB-miss per access, L1-TLB misses are typically size of tree / total cache size), z ~= access time of least cache or main memory that can hold the entire tree.

On the other hand the "average case" quicksort streams memory at maximum pre-fetcher speed. Only drawback here is the average case also cause a stream to be written back. And after some partitions the entire active set sit in caches and will get streamed quicker.

Both algorithms suffers heavily from branch mis-predictions but quicksort, just need to backup a bit, B-Tree additionally needs to read in a new address to fetch from as it has a data dependency which quicksort doesn't.

Few algoritmes are implemented as pure theoretically functions. Nearly all have some heuristics to fix their worst problems, Tim-sort excepted as its build of heuristics.

merge-sort and quick-sort are often checked for already sorted ranges, just like Tim-sort. Both also have an insertion sort for small sets, typically less than 16 elements, Tim-sort is build up of these smaller sets. The C++ std::sort is a quicksort hybrid with insertion sort, with the additional fallback for the worst case behaviour, if the dividing exceed twice the expected depth it changes to a heap-sort algorithm.

The original quicksort used the first element of the array as pivot, this was quickly abandoned for a (pseudo)random element, typically the middle. Some implementations changed to median-of-three (random elements) to get a better pivot, recently a median-of-5-median (of all elements) was used, and last I saw in some presentation from Alexandrescu was a median-of-3-medians (of all elements) to get the a pivot that was close to the actual median (1/3 or a 1/5 of the span).

Surt
  • 161
  • 1
  • 4
1

Consider the following general question:

Here is an $O(n\log n)$ sorting algorithm. Why use quicksort (or timsort, or whatever is used in some library) rather than my algorithm?

There are several possible types of answers:

  1. Your algorithm is worse than quicksort in some sense, say it is slower on average.

  2. Your algorithm has similar performance to quicksort. Libraries need only one algorithm, so they chose quicksort for historical reasons.

  3. Your algorithm is better than quicksort in some sense (say worst case complexity), but worse in some other sense (say average case complexity). Libraries prefer the tradeoffs of quicksort.

  4. Your algorithm is better than quicksort, but is not widely known and so not implemented in libraries.

  5. Your algorithm is implemented in some libraries, but they are too obscure for you to realize.

But the real answer is:

Library designers implement some sorting algorithm they know. Later on, other people might implement a different algorithm. Nobody is claiming that whatever algorithm is implemented is the best algorithm in all (or even some) applications. People for whom this is important implement their own algorithms.

Raphael
  • 72,336
  • 29
  • 179
  • 389
Yuval Filmus
  • 276,994
  • 27
  • 311
  • 503
  • Good points, but I disagree with parts of your conclusion. Good library developers are very careful to pick efficient core algorithms! There may be better choices for many specific scenarios, but that's just the presence of tradeoffs. – Raphael Dec 04 '16 at 02:10