Merge Sort solves the Sorting problem.
Merge Sort uses the divide-and-conquer approach. It proceeds as follows:
Before we can give a more formal description of the algorithm we must discuss how to accomplish the merge step. If you are unfamiliar with how this is done, please read the Merge section before continuing.
To sort an array \(A\) of length \(n\), we let \(left=0\) and \(right=n-1\) and proceed as follows. (Note: it treats both \(left\) and \(right\) as inclusive endpoints.)
mergeSort(A,0,n-1)
. An alternative version for Python is given
that takes advantage of some shortcuts, but it is not as efficient as the first version.
public static void mergeSort(int[] A, int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(A, left, mid);
mergeSort(A, mid + 1, right);
merge(A, left, mid, right);
}
}
public static void merge(int[] A, int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
int[] L = new int[n1];
int[] R = new int[n2];
// copy into temporary lists
for (int i = 0; i < n1; i++)
L[i] = A[left + i];
for (int j = 0; j < n2; j++)
R[j] = A[mid + 1 + j];
int i = 0, j = 0, k = left;
// merge back into A
while (i < n1 && j < n2) {
if (L[i] <= R[j])
A[k++] = L[i++];
else
A[k++] = R[j++];
}
// copy any remaining elements of L (if R is exhausted)
while (i < n1)
A[k++] = L[i++];
// copy any remaining elements of R (if L is exhausted)
while (j < n2)
A[k++] = R[j++];
}
void mergeSort(int A[], int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(A, left, mid);
mergeSort(A, mid + 1, right);
merge(A, left, mid, right);
}
}
void merge(int A[], int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
int* L = new int[n1];
int* R = new int[n2];
// copy into temporary lists
for (int i = 0; i < n1; i++)
L[i] = A[left + i];
for (int j = 0; j < n2; j++)
R[j] = A[mid + 1 + j];
int i = 0, j = 0, k = left;
// merge back into A
while (i < n1 && j < n2) {
if (L[i] <= R[j])
A[k++] = L[i++];
else
A[k++] = R[j++];
}
// copy any remaining elements of L (if R is exhausted)
while (i < n1)
A[k++] = L[i++];
// copy any remaining elements of R (if L is exhausted)
while (j < n2)
A[k++] = R[j++];
// delete dynamically allocated memory
delete[] L;
delete[] R;
}
def merge_sort(A, left, right):
if left < right:
mid = left + (right - left) // 2
merge_sort(A, left, mid)
merge_sort(A, mid + 1, right)
merge(A, left, mid, right)
def merge(A, left, mid, right):
n1 = mid - left + 1
n2 = right - mid
# copy into temporary lists
L = [A[left + i] for i in range(n1)]
R = [A[mid + 1 + j] for j in range(n2)]
i = j = 0 # current indices in L and R
k = left # current index in A where we write
# merge back into A
while i < n1 and j < n2:
if L[i] <= R[j]:
A[k] = L[i]
i += 1
else:
A[k] = R[j]
j += 1
k += 1
# copy any remaining elements of L (if R is exhausted)
while i < n1:
A[k] = L[i]
i += 1
k += 1
# copy any remaining elements of R (if L is exhausted)
while j < n2:
A[k] = R[j]
j += 1
k += 1
def merge_sort(A):
if len(A) <= 1:
return A
mid = len(A) // 2
left = merge_sort(A[:mid])
right = merge_sort(A[mid:])
return merge(left, right)
def merge(left, right):
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
result.append(left[i]); i += 1
else:
result.append(right[j]); j += 1
result.extend(left[i:])
result.extend(right[j:])
return result
Time Complexity:
Let \(T(n)\) be the time (number of basic operations) required by Merge Sort to sort an array of length n
.
We can break each call into three parts:
Since sorting an array of size 1 takes constant time, we get
\[ T(n) \;=\; 2\,T\!\bigl(\tfrac n2\bigr)\;+\;\alpha\;+\;\beta\,n, \quad T(1) = 1. \]
Assuming we only want a bound on the complexity, we can simplify this to
\[ T(n) \;=\; 2\,T\!\bigl(\tfrac n2\bigr)\;+\;n, \quad T(1) = 1. \]
There are various ways of solving this recurrence relation (backward substitution, forward substitution, Master Theorem) that all give us \[T(n)=\Theta(n\log n).\]
Notice that the complexity does not depend on the initial order of elements. Thus, Merge Sort takes a predictable amount of time to sort any array of a given size.
Space Complexity: Merge Sort requires two types of extra space:
Thus, overall the space complexity is \(\Theta(\log n\;+\;n)\;=\;\Theta(n)\).
There are several well-known variations and optimizations:
[5,3,8,1,2,7,4,6]
by hand.[8,7,6,5,4,3,2,1]
and [1,2,3,4,5,6,7,8]
.