The Median-of-Medians Algorithm
austinrochford.com
austinrochford.com
- Random pivot (ie Median of 1) has 3.39N comparisons
- Median of 3 has 2.75N
If you want the fastest possible algorithm you should follow
http://dx.doi.org/10.1109/TSP.2012.2197394
which proposes to choose the median of N^{2/3}1/(4pi)^{1/3} elements as the pivot and then also uses a different strategy to choose the second pivot (close to the median yet "safe").
Another fast algorithm is Floyd & Rivest's SELECT (yes the same crypto Rivest) which is also asymptotically optimal and implementations exist. (Paper title: "Expected time bounds for selection")
You certainly can:
1. Run the randomized algorithm
2. If if the usual way takes too long (more than O(n) for whatever constant factor makes sense to you), just stop doing more work and switch to the deterministic algorithm
Now you get the best of both speeds, within a small constant factor (like 2).
His lecture notes from his course at Carnegie Mellon describe this algorithm quite clearly [1].
[0] http://en.wikipedia.org/wiki/Manuel_Blum
[1] http://www.cs.cmu.edu/afs/cs/academic/class/15451-s07/www/le...
Actually, if you use lazy data structures, then sorting the list lazily and taking i-th element will give you the best possible complexity: http://en.wikipedia.org/wiki/Selection_algorithm#Language_su...
In Haskell, it is nothing more than "ithSmallest xs i = sort xs !! i".
In the standard idiom,
smallest = head . sort
we're only looking for the case of k=1, so we can do it in O(n) time.Note that if you used a lazy BST, then you could probably still get the last element in O(n) run time, but your example code doesn't do that. AFAIK, no standard library routine exists for this.
You don't have to fully sort the list before determining the kth element (again assuming a sufficiently lazy implementation). Once you know the element is in the second half of the list, the sort simply will never sort the first half.
- That 'sort' will produce the items of the list in some order ('third item is 2nd largest, 17th item is 34th largest,...).
- Lazy evaluation cannot stop before the sort produces 'x is i-th'.
- 'sort' does not know what is done with its output (i.e. it does not know the value of i)
If these are true, Evie can pick i in such a way that it is produced last, that is: such that sort must sort the complete list. That requires O(n log n) time.
The only way around this I can see is if the language recognizes the idiom and special-cases it to pick a sort algorithm, based on both the sequence xs and the requested index i. Does Haskell contain such a special case?
`sort xs` evaluates to a data structure which contains the original unsorted sequence.
When asked for the ith element, the datastructure uses quickselect to produce the ith smallest element, while also partially sorting the sequence.
Repeated requests for the ith element will become faster and faster, as the sequence becomes more and more sorted.
I wonder if there are other possible implementations?
There is a very nice and simple probabilistic algorithm instead.