Find median of unsorted array in $O(n)$ time

To find the median of an unsorted array, we can make a min-heap in $O(n\log n)$ time for $n$ elements, and then we can extract one by one $n/2$ elements to get the median. But this approach would take $O(n \log n)$ time.

Can we do the same by some method in $O(n)$ time? If we can, then how?

This is a special case of a selection algorithm that can find the $k$th smallest element of an array with $k$ is the half of the size of the array. There is an implementation that is linear in the worst case.

Generic selection algorithm

First let's see an algorithm find-kth that finds the $k$th smallest element of an array:

find-kth(A, k)
pivot = random element of A
(L, R) = split(A, pivot)
if k = |L|+1, return pivot
if k ≤ |L|  , return find-kth(L, k)
if k > |L|+1, return find-kth(R, k-(|L|+1))


The function split(A, pivot) returns L,R such that all elements in R are greater than pivot and L all the others (minus one occurrence of pivot). Then all is done recursively.

This is $O(n)$ in average but $O(n^2)$ in the worst case.

Linear worst case: the median-of-medians algorithm

A better pivot is the median of all the medians of sub arrays of A of size 5, by using calling the procedure on the array of these medians.

find-kth(A, k)
B = [median(A[1], .., A[5]), median(A[6], .., A[10]), ..]
pivot = find-kth(B, |B|/2)
...


This guarantees $O(n)$ in all cases. It is not that obvious. These powerpoint slides are helpful both at explaining the algorithm and the complexity.

Note that most of the time using a random pivot is faster.

• Is this size 5 standard ? What if size of A is less than 5 ? – Jayesh Feb 21 '16 at 20:02
• For any fixed n, the complexity is constant, unless it is infinite. So, you can use any valid algorithm with finite complexity for such special case, even if it was O(2^n). For a fixed n (i.e. at most 4 in out case), the complexity is at most O(2^4) = O(1). – v6ak Apr 23 '16 at 18:42
• On the first algorithm: return A[k] is incorrect (unless A is sorted which would make the algorithm moot). If split happened to divide A such that k = |L| + 1 you still don't know where the kth element is. Your base case is when |A| = 1 else you still need to make one of the two recursive calls. – wcochran Apr 30 '16 at 4:48
• @NickCaplinger fixed using web.archive.org – jmad May 17 '16 at 1:06
• Isn't the worst case for the generic selection algorithm O(NlogN)? Even if the recursive call leaves only 10% of the array after each call, then it's still a logarithm in basis 10. – octavian Mar 29 '17 at 14:40

There is a randomized Monte Carlo algorithm to do this. It is described in [MU2017]. It is a linear time algorithm that fails to produce a solution with probability at most $n^{-1/4}$. As discussed in [MU2017], it is significantly simpler than the deterministic $O(n)$ algorithm and yields a smaller constant factor in the linear running time.

The main idea of the algorithm is to use sampling. We have to find two elements that are close together in the sorted order of the array and that have the median lie between them. See the reference [MU2017] for a complete discussion.

[MU2017] Michael Mitzenmacher and Eli Upfal. "Probability and Computing: Randomization and Probabilistic Techniques in Algorithms and Data Analysis," chapter 3, pages 57-62. Cambridge University Press, Second edition, 2017.