C Program: Merge Sort
The insertion sort algorithm discussed in our previous tutorial uses an incremental approach to sort. Merge sort however uses the divide-and-conquer approach to sort numbers, which is recursive in nature.
Consider the below sequence of unsorted numbers:
( 6 -1 2 1 8 3 )
Here we will illustrate the use of Merge Sort to sort the above sequence in ascending order, which will result in the above set of numbers being sorted as follows.
( -1 1 2 3 6 8 )
The given $n$ sequence of numbers is divided into two subsequences of $\frac{n}{2}$ length each. These two subsequences are further sorted recursively using merge sort. They are then merged back into a single sequence.
The actual merging is perfomed inside the auxiliary merge()
function which takes the parameters $A$, $p$, $q$ and $r$ where $A$ is the array containing the numbers and $p$, $q$ and $r$ are indices of array elements such that $p \le q \lt r$. The merge()
function assumes that the two subarrays $A[p .. q]$ and $A[q + 1 .. r]$ are in sorted order and then merge them into a single sorted array replacing the original $A[p .. r]$ array.
The mergesort()
function takes in the parameters $A$, $p$ and $r$, where is $A$ is the array of numbers to be sorted, and $p$ and $r$ are the indices of its first and last elements. As long as $p \lt r$, the algorithm goes on dividing the array into two equal subarrays with $A[p .. q]$ consisting of $\lceil \frac{n}{2} \rceil$ elements and $A[q+1 .. r]$ consisting of $\lfloor \frac{n}{2} \rfloor$ elements, recursively. When $p = r$, the divided subarray has only one element and the array is already sorted.
From here, the earlier merge()
function is invoked to merge 1-item sequences into sorted sequences of length two. And next these two-item sequences are merged into sorted sequences of length four, and so on till the last two sequences of length $\frac{n}{2}$ are merged back to a single sorted array of original length $n$.
The C program below illustrates the merge sort algorithm we discussed above.
#include <stdio.h>
void merge(int A[], int p, int q, int r);
void mergesort(int A[], int p, int r);
int main() {
int A[] = {6,-1,2,1,8,3}, n, i;
// the size of given array
n = 6;
// merge sort
mergesort(A, 0, n-1);
// printing the sorted array
for(i = 0; i < n; i++) {
printf("%d ", A[i]);
}
return 0;
}
void merge (int A[], int p, int q, int r) {
int n1 = q - p + 1;
int n2 = r - q;
int L[n1], R[n2];
int i, j, k;
for(i = 0; i < n1; i++) {
L[i] = A[p+i];
}
for(j = 0; j < n2; j++) {
R[j] = A[q+1+j];
}
i = 0;
j = 0;
k = p;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
A[k] = L[i];
i++;
}
else {
A[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
A[k] = L[i];
i++;
k++;
}
while (j < n2) {
A[k] = R[j];
j++;
k++;
}
}
void mergesort (int A[], int p, int r) {
if (p < r) {
int q = (p+r)/2;
mergesort(A,p,q);
mergesort(A,q+1,r);
merge(A,p,q,r);
}
}
On compiling and running the above C program, we get the sorted output as
$ ./a.out
-1 1 2 3 6 8
With Array Input
Instead of pre-arranged sequence of numbers, we can modify the above C program to read numbers dynamically. In the program, the size of the array A[]
is restricted to just 100, but this can be enhanced better by making use of dynamic memory allocation, which we will cover in other example programs.
#include <stdio.h>
void merge(int A[], int p, int q, int r);
void mergesort(int A[], int p, int r);
int main() {
int A[100], n, i;
printf("Enter the dimension of the array: ");
scanf("%d", &n);
// array input
for(i = 0; i < n; i++) {
printf("Enter A[%d]: ", i);
scanf("%d", &A[i]);
}
// merge sort
mergesort(A, 0, n-1);
// printing the sorted array
for(i = 0; i < n; i++) {
printf("%d ", A[i]);
}
return 0;
}
void merge (int A[], int p, int q, int r) {
int n1 = q - p + 1;
int n2 = r - q;
int L[n1], R[n2];
int i, j, k;
for(i = 0; i < n1; i++) {
L[i] = A[p+i];
}
for(j = 0; j < n2; j++) {
R[j] = A[q+1+j];
}
i = 0;
j = 0;
k = p;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
A[k] = L[i];
i++;
}
else {
A[k] = R[j];
j++;
}
k++;
}
while (i < n1) {
A[k] = L[i];
i++;
k++;
}
while (j < n2) {
A[k] = R[j];
j++;
k++;
}
}
void mergesort (int A[], int p, int r) {
if (p < r) {
int q = (p+r)/2;
mergesort(A,p,q);
mergesort(A,q+1,r);
merge(A,p,q,r);
}
}
Merge Sort has the average time complexity of $O(n \log(n))$, which is much efficient compared to Insertion Sort.