Inspecting C's qsort Through Animation
nullprogram.com
nullprogram.com
I see this stated frequently, but I rarely see evidence to back it up.
I grabbed his code, removed the drawing function and tested it with perf [1]. (Using glibc's qsort).
First test was with 1 million elements in the array. That's 4 MB of data, so it fits in L3 cache with room to spare.
Perf reports an average of 1.02 instructions/cycle with a cache miss rate of 2.829%.
Second test: 10 million elements (40 MB). Doesn't fit in cache.
Perf says: 0.95 instructions/cycle, cache miss rate of 37.352%.
Third test has 500 million elements (2 GB). Fits in RAM but not cache.
1.01 instructions/cycle and a cache miss rate of 66.555%.
If the CPU was stalling frequently, waiting for data, I would expect the number of instructions/cycle to drop dramatically as the cache miss rate increases. It drops slightly from 4MB to 40MB, but inexplicable increases from 40MB to 2GB.
So I see two possibilities:
1. I'm dumb and misinterpreting the perf data.
2. The out-of-order core can work around data stalls so effectively for this algorithm, the cache miss rate doesn't really matter.
http://git.musl-libc.org/cgit/musl/commit/?id=22263709eda9f7...
Heapsort (And thus smoothsort) are not recursive, so they require a constant amount of memory for all inputs.
(Which I was only reading because I was erroneously thinking that quicksort was O(1) memory – I was completely forgetting stack space.)
[1]: https://en.wikipedia.org/wiki/Quicksort#Space_complexity
There is an explanation provided that may be the reason, but it is not entirely convincing.
Smoothsort is a variation of heapsort that performs especially well on nearly sorted inputs. It’s a pretty complicated beast and it does take some effort to wrap one’s head around it. Keith Schwarz has posted a nice walkthrough that the interested reader should check out.
Considering that musl libc puts simplicity among its design goals, the choice of smoothsort could seem odd. The code is however clean and readable and getting an O(nlogn)O(nlogn) worst case with near linear complexity for nearly sorted inputs is a pretty sweet deal.Why then is it slower in this case, and not as widely used? Part of the reason is that smoothsort is simply not very widely known, and thus not as many people know how it works compared to Quicksort or Mergesort. Nothing that, while complexity is important to take into account and looks good on paper, complexity leaves off the 'constants', which is generally what people attribute heapsort's (And thus, smoothsort's) higher number of comparisons.
All that noted, smoothsort (and heapsort) have the big advantages of being in-place (merge is not), requiring O(1) extra space in the worst case (Quicksort can require up to O(n) extra space), and has a guaranteed upper-bound of O(n lg n) in the worst case (Quicksort can degenerate to O(n^2) performance with bad data). This means that heapsort may not always outperform Quicksort, but gives better guarantees about speed and data usage then Quicksort (And much better then Mergesort, which requires a lots of extra allocated data). Smoothsort is essentially just a better heapsort which functions even better when the list is close to already sorted.
While quick sort doesn't guarantee the ordering of equal elements, you at least want it to be the same each time you run a particular compile of your program.
The BSD implementation is quicksort, which doesn't have a duplicate (AKA auxiliary) array. Their implementation of mergesort has an auxiliary/duplicate array for the actual merging - that's common. In-place mergesorts exist, but the effort isn't usually worth it.
You can, however, eliminate the need for copying to the duplicate array (which they may do) by invoking sort twice - once takes input from the actual array and puts the sorted output in the duplicate, and the second takes from the duplicate and puts it back into the default. Somehow, you can merge the two together to speed up the algorithm (I personally don't know how, however they can be found implemented here: http://algs4.cs.princeton.edu/22mergesort/MergeX.java.html)