MERGE SORT - Analysis and Design of Algorithms
1. Introduction:
Merge Sort is a highly efficient and stable sorting algorithm that uses the divide-and-conquer
paradigm. Developed by John von Neumann in 1945, it works by recursively dividing the array into
two halves, sorting each half, and then merging the sorted halves back together.
2. Problem Statement:
Given an unsorted array of n elements, the task is to sort the elements in ascending order using the
Merge Sort algorithm.
3. Technique:
Merge Sort divides the array into two halves, recursively sorts them, and then merges the sorted
halves to produce the final sorted array. This merging process ensures that the array becomes
sorted as we combine smaller sorted arrays into larger ones.
4. Steps:
- Divide the unsorted list into n sublists, each containing one element.
- Repeatedly merge sublists to produce new sorted sublists until there is only one sublist remaining.
5. Algorithm:
MERGE_SORT(arr, left, right)
if left < right
mid = (left + right) // 2
MERGE_SORT(arr, left, mid)
MERGE_SORT(arr, mid + 1, right)
MERGE(arr, left, mid, right)
MERGE(arr, left, mid, right)
create left_subarray and right_subarray
while elements remain in both subarrays
compare and add smaller to result
copy remaining elements
6. Implementation in C:
#include <stdio.h>
void merge(int arr[], int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
int L[n1], R[n2];
for (int i = 0; i < n1; i++)
L[i] = arr[l + i];
for (int j = 0; j < n2; j++)
R[j] = arr[m + 1 + j];
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
k++;
while (i < n1) {
arr[k] = L[i];
i++;
k++;
while (j < n2) {
arr[k] = R[j];
j++;
k++;
void mergeSort(int arr[], int l, int r) {
if (l < r) {
int m = l + (r - l) / 2;
mergeSort(arr, l, m);
mergeSort(arr, m + 1, r);
merge(arr, l, m, r);
}
}
void printArray(int A[], int size) {
for (int i = 0; i < size; i++)
printf("%d ", A[i]);
printf("\n");
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int arr_size = sizeof(arr) / sizeof(arr[0]);
mergeSort(arr, 0, arr_size - 1);
printf("Sorted array: \n");
printArray(arr, arr_size);
return 0;
7. Implementation in Python:
def merge_sort(arr):
if len(arr) > 1:
mid = len(arr) // 2
L = arr[:mid]
R = arr[mid:]
merge_sort(L)
merge_sort(R)
i=j=k=0
while i < len(L) and j < len(R):
if L[i] < R[j]:
arr[k] = L[i]
i += 1
else:
arr[k] = R[j]
j += 1
k += 1
while i < len(L):
arr[k] = L[i]
i += 1
k += 1
while j < len(R):
arr[k] = R[j]
j += 1
k += 1
arr = [12, 11, 13, 5, 6, 7]
merge_sort(arr)
print("Sorted array is:", arr)
8. Implementation in Java:
public class MergeSort {
void merge(int arr[], int l, int m, int r) {
int n1 = m - l + 1;
int n2 = r - m;
int L[] = new int[n1];
int R[] = new int[n2];
for (int i = 0; i < n1; ++i)
L[i] = arr[l + i];
for (int j = 0; j < n2; ++j)
R[j] = arr[m + 1 + j];
int i = 0, j = 0, k = l;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
k++;
while (i < n1) {
arr[k] = L[i];
i++;
k++;
while (j < n2) {
arr[k] = R[j];
j++;
k++;
void sort(int arr[], int l, int r) {
if (l < r) {
int m = l + (r - l) / 2;
sort(arr, l, m);
sort(arr, m + 1, r);
merge(arr, l, m, r);
public static void main(String args[]) {
int arr[] = {12, 11, 13, 5, 6, 7};
int n = arr.length;
MergeSort ob = new MergeSort();
ob.sort(arr, 0, n - 1);
System.out.println("Sorted array:");
for (int i = 0; i < n; ++i)
System.out.print(arr[i] + " ");
9. Expected Output:
Sorted array: 5 6 7 11 12 13
10. Advantages:
- Stable sort.
- Guarantees O(n log n) time complexity.
- Suitable for large data sets.
11. Disadvantages:
- Requires additional space (not in-place).
- Slower than in-place sorting algorithms for small arrays.
12. Real-World Applications:
- Used in external sorting (large datasets that don't fit in memory).
- Applied in databases and bioinformatics.
- Suitable in scenarios requiring stable sorting.
13. Conclusion:
Merge Sort is a powerful and reliable sorting algorithm that consistently provides good performance.
Its stability and predictable time complexity make it ideal for many critical applications, especially
when large datasets or stability requirements are involved. Despite requiring additional memory, it is
preferred in systems where performance and consistency are critical.