Merge Sort#
Contents#
Merge sort can be attributed to John Von Neumann around 1945.
Merge sort is a stable sorting algorithm, which means that duplicate elements retain the same relative ordering both before and after the sorting operation.
Merge sort is based on the idea of sorted array merge.
Divide
The input array is partitioned into two subarrays based on the array’s midpoint.
Conquer
Each subarray is recursively sorted. The base case occurs when a subarray contains a single element, at which point it is trivially sorted.
Combine
The resulting sorted subarrays are combined via SORTED_ARRAY_MERGE
.
INPUT an array A[0:n - 1] of n values where n >= 1, l = 0, r = n - 1
OUTPUT the array sorted in ascending order
MERGE_SORT(A, l, r)
1 if l == r
2 return A[l]
3
4 m = l + (r - l) // 2
5 a1 = MERGE_SORT(A, l , m)
6 a2 = MERGE_SORT(A, m + 1, r)
7
8 return SORTED_ARRAY_MERGE(a1, a2)
Correctness#
Base Case
Let \(|A| = 1\). \(A\) is trivially sorted and so
mergesort
is guaranteed to produce the correct result.
Inductive Step
Assume that
mergesort
produces the correct output for an array of size \(n/2\).Then
mergesort
produces the correct output for an array of size \(n\) by sorting two arrays of size \(n/2\) and then combining them viasorted-merge
.
Therefore mergesort
is correct for an array of any size \(n\) since an array will be sub divided until it reaches the base case. The inductive step demonstrates that so long as mergesort
is correct for some sub problem it is correct for all sub problems.
Complexity#
Time#
The time complexity of mergesort
is \(T(n) = 2T(n/2) + \Theta(n)\) where the term \(2T(n/2)\) represents the number of sub problems times the cost of recursively sorting a sub problem and the term \(\Theta(n)\) is the cost of running the comparison operation. The comparison operation runs in linear time with respect to the combined size of the two input arrays. According to the Master Theorem the time complexity of mergesort
becomes
\(a = 2, b = 2, d = 1 \implies \Theta(n \log n)\)
worst case \(T(n) = \Theta(n \log n)\)
Space#
Merge sort has space requirement \(S(n) = \Theta(n)\) due to the sorted-array merge operation.
mergesort
doesn’t create any auxiliary data structures, and it only uses a constant number of variables. But there are two hidden costs:
the space cost associated with
sorted-merge
the space cost of the recursive call stack
\(S(n) = S(n/2) + \Theta(n)\)
The first term is not \(2S(n/2)\) because sub problems are solved sequentially, one after the other, and so memory is only expended on a single sub problem at a time.
By the Master Theorem we see that \(a = 1, b = 2, d = 1 \implies (d = 1) \gt 0 = \log_{(b = 2)} (a = 1)\). In other words, the combination operation dominates the cost of solving the sub problems and so the space complexity of mergesort
is \(\Theta(n^d) = \Theta(n^{(1)}) = \Theta(n)\).
Alternatively, we can think about the space complexity as follows. The call stack contains \(\Theta(\log n)\) stack frames because the size of the array reduces by half each recursive call and the recursive calls stop when \(n = 1\). In the worst case analysis, each stack frame requires \(O(n)\) space (but in reality most of them require less).
\(S(n) = \Theta(\log n) + \Theta(n) = \Theta(n)\)
There are versions of mergesort that do not require auxiliary arrays, but these versions tend to have the worst performance in practice.
Mergesort vs quicksort
Mergesort has a better worst-case time complexity than quicksort.
\( T(n) = \begin{cases} \Theta(n \lg n) & \text{mergesort} \\ \Theta(n^2) & \text{quicksort} \\ \end {cases} \)
However, quicksort performs as good as mergesort asymptotically in expectation.
\( T(n) = \begin{cases} \Theta(n \lg n) & \text{mergesort} \\ \Theta(n \lg n) & \text{quicksort} \\ \end {cases} \)
In practice, quicksort is usually the faster of the two sorting algorithms since the constraints associated with its time complexity are lower.
In comparison to quicksort, mergesort requires more auxiliary space.
\( S(n) = \begin{cases} \Theta(n) & \text{mergesort} \\ \Theta(\lg n) & \text{quicksort} \\ \end {cases} \)
Resources#
https://www.digitalocean.com/community/tutorials/merge-sort-algorithm-java-c-python