Merge Sort in C: Algorithm, Code, and Complete Guide
By Rahul Singh
Updated on Jun 09, 2026 | 7 min read | 2.83K+ views
Share:
Looks like you're browsing from the
United StatesSome programs may not be available in your location
Some programs may not be available in your location
Switch to upGrad USAll courses
Certifications
More
By Rahul Singh
Updated on Jun 09, 2026 | 7 min read | 2.83K+ views
Share:
Table of Contents
Merge sort in C is a widely used sorting algorithm that follows the divide-and-conquer approach. Instead of sorting an entire array at once, it repeatedly splits the array into smaller halves, sorts those smaller sections recursively, and then merges them back together in the correct order to produce a fully sorted array.
Because of its consistent O(n log n) time complexity and ability to handle large datasets efficiently, merge sort is considered one of the most reliable sorting algorithms in computer science. It is commonly used in applications where stable and predictable sorting performance is required.
In this blog, you will learn exactly how merge sort works, how to write merge sort code in C from scratch, how to trace through a dry run, and where it is actually used in real-world systems.
Transform your career with upGrad’s Data Science Course. Learn from industry experts, work on hands-on projects, and gain the skills top employer’s demand.
The key idea is simple: sorting two small arrays and merging them is far easier than sorting one large array directly.
Here is the high-level flow:
This process repeats until each sub-array has only one element, which is already considered sorted.
Feature |
Merge Sort |
Bubble Sort |
Quick Sort |
| Time Complexity (Worst) | O(n log n) | O(n²) | O(n²) |
| Time Complexity (Best) | O(n log n) | O(n) | O(n log n) |
| Space Complexity | O(n) | O(1) | O(log n) |
| Stable Sort | Yes | Yes | No |
| Best for Large Data | Yes | No | Yes |
Merge sort algorithm in C is preferred when:
Also Read: Types of Linked Lists
Before writing any merge sort program in C, understand the two core functions you need to build:
mergeSort(arr, left, right)
if left < right:
mid = (left + right) / 2
mergeSort(arr, left, mid)
mergeSort(arr, mid + 1, right)
merge(arr, left, mid, right)
Also Read: Insertion Sort in C: Algorithm, Code, and Step-by-Step Guide
The merge step takes two sorted sub-arrays and combines them into one sorted array. It uses a temporary array to hold values while comparing elements from both halves.
Let's trace merge sort on the array: [38, 27, 43, 3]
Step 1: Divide
[38, 27, 43, 3]
[38, 27] [43, 3]
[38] [27] [43] [3]
Step 2: Merge
[38] + [27] → [27, 38]
[43] + [3] → [3, 43]
[27, 38] + [3, 43] → [3, 27, 38, 43]
Each merge step compares elements from both halves one by one and places the smaller one first. This is what makes the final result sorted.
Also Read: Data Structures and Algorithms (DSA)
Here is the complete merge sort implementation in C:
#include <stdio.h>
#include <stdlib.h>
// Merge two sorted sub-arrays into one
void merge(int arr[], int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
// Create temporary arrays
int *L = (int *)malloc(n1 * sizeof(int));
int *R = (int *)malloc(n2 * sizeof(int));
// Copy data into temp arrays
for (int i = 0; i < n1; i++)
L[i] = arr[left + i];
for (int j = 0; j < n2; j++)
R[j] = arr[mid + 1 + j];
int i = 0, j = 0, k = left;
// Merge L and R back into arr
while (i < n1 && j < n2) {
if (L[i] <= R[j]) {
arr[k] = L[i];
i++;
} else {
arr[k] = R[j];
j++;
}
k++;
}
// Copy remaining elements of L, if any
while (i < n1) {
arr[k] = L[i];
i++;
k++;
}
// Copy remaining elements of R, if any
while (j < n2) {
arr[k] = R[j];
j++;
k++;
}
free(L);
free(R);
}
// Recursive function to divide and sort
void mergeSort(int arr[], int left, int right) {
if (left < right) {
int mid = left + (right - left) / 2;
mergeSort(arr, left, mid);
mergeSort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
// Utility to print an array
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++)
printf("%d ", arr[i]);
printf("\n");
}
// Main function
int main() {
int arr[] = {38, 27, 43, 3, 9, 82, 10};
int n = sizeof(arr) / sizeof(arr[0]);
printf("Original array: ");
printArray(arr, n);
mergeSort(arr, 0, n - 1);
printf("Sorted array: ");
printArray(arr, n);
return 0;
}
Output:
Original array: 38 27 43 3 9 82 10
Sorted array: 3 9 10 27 38 43 82
Also Read: Understanding While Loop in Python with Examples
Understanding complexity is essential for any developer. Here is what merge sort looks like across different cases:
Case |
Complexity |
When It Happens |
| Best Case | O(n log n) | Always, regardless of input |
| Average Case | O(n log n) | Randomly ordered input |
| Worst Case | O(n log n) | Even reverse-sorted arrays |
This is one of merge sort's biggest strengths. Unlike quick sort, the worst case for merge sort never degrades to O(n²).
The log n factor comes from the number of times you can divide the array in half. The n factor comes from the work done during each merge step.
Also Read: Time and Space Complexity in Machine Learning Algorithms Explained
Merge sort requires O(n) auxiliary space because it creates temporary arrays during the merge step. This is its main drawback compared to in-place algorithms like quick sort or heap sort.
For memory-constrained environments, this is worth considering before choosing merge sort.
The recurrence relation for merge sort algorithm in C is:
T(n) = 2T(n/2) + O(n)
Solving this using the Master Theorem gives us O(n log n).
Also Read: Top Time Complexities that every Programmer Should Learn
The recursive approach is clean and easy to understand. But for very deep recursion (large arrays), stack overflow can be a concern. The iterative (bottom-up) approach solves this.
Instead of dividing top-down, it merges from the bottom up, starting with sub-arrays of size 1, then 2, then 4, and so on.
#include <stdio.h>
#include <stdlib.h>
void merge(int arr[], int left, int mid, int right) {
int n1 = mid - left + 1;
int n2 = right - mid;
int *L = (int *)malloc(n1 * sizeof(int));
int *R = (int *)malloc(n2 * sizeof(int));
for (int i = 0; i < n1; i++) L[i] = arr[left + i];
for (int j = 0; j < n2; j++) R[j] = arr[mid + 1 + j];
int i = 0, j = 0, k = left;
while (i < n1 && j < n2) {
if (L[i] <= R[j]) arr[k++] = L[i++];
else arr[k++] = R[j++];
}
while (i < n1) arr[k++] = L[i++];
while (j < n2) arr[k++] = R[j++];
free(L);
free(R);
}
void mergeSortIterative(int arr[], int n) {
for (int size = 1; size < n; size *= 2) {
for (int left = 0; left < n - size; left += 2 * size) {
int mid = left + size - 1;
int right = (left + 2 * size - 1 < n - 1) ? left + 2 * size - 1 : n - 1;
merge(arr, left, mid, right);
}
}
}
int main() {
int arr[] = {12, 11, 13, 5, 6, 7};
int n = sizeof(arr) / sizeof(arr[0]);
mergeSortIterative(arr, n);
printf("Sorted: ");
for (int i = 0; i < n; i++) printf("%d ", arr[i]);
printf("\n");
return 0;
}
Output: Sorted: 5 6 7 11 12 13
When to use the iterative version:
Also Read: Top 12 Stack Examples in Real Life
Merge sort is not just a textbook algorithm. It shows up in real systems regularly.
Criterion |
Merge Sort |
Quick Sort |
| Worst-case time | O(n log n) | O(n²) |
| Memory usage | O(n) | O(log n) |
| Stable sort | Yes | No |
| Linked lists | Preferred | Not ideal |
| In-place sorting | No | Yes |
| Cache efficiency | Lower | Higher |
Use merge sort when stability matters or when you are sorting linked lists. Use quick sort when memory is limited and data is in an array.
Even experienced programmers make these mistakes when writing merge sort code in C:
Merge sort in C is a powerful, stable, and consistent sorting algorithm with a guaranteed O(n log n) time complexity in all cases. It is clean to implement, easy to reason about, and widely used in both competitive programming and production systems.
Start with the recursive version to understand the logic. Then try the iterative version to see how it avoids recursion overhead. Once you are comfortable, explore merge sort's role in counting inversions and external sorting to see just how versatile this algorithm really is.
Want personalized guidance on AI and upskilling? Speak with an expert for a free 1:1 counselling session today.
Merge sort in C is a divide and conquer sorting algorithm. It splits an array into two halves, recursively sorts each half, and then merges both sorted halves into one final sorted array. This process repeats until the entire array is sorted.
Merge sort has a time complexity of O(n log n) in all cases, best, average, and worst. This makes it more predictable than quick sort, which can degrade to O(n²) in the worst case with poor pivot choices.
Yes, merge sort is a stable sorting algorithm. When two elements have equal values, merge sort preserves their original order in the sorted output. This property is important for multi-key sorting in databases and applications.
Merge sort requires O(n) auxiliary space because it creates temporary arrays during the merge step. This is its primary disadvantage compared to in-place algorithms like heap sort or quick sort.
Merge sort always runs in O(n log n) time and is stable, but uses extra O(n) space. Quick sort is in-place and cache-efficient but has an O(n²) worst case and is not stable. Choose merge sort for linked lists and stability; choose quick sort for array-based, memory-sensitive programs.
Yes, merge sort can be implemented iteratively using a bottom-up approach. Instead of dividing top-down, it starts by merging sub-arrays of size 1, then size 2, then 4, and so on. This eliminates recursion overhead and is safer for very large arrays.
Merge sort works well with linked lists because it does not require random access to elements. It only needs to traverse the list sequentially to split and merge, which matches how linked lists are accessed. Quick sort and heap sort are much harder to apply on linked lists.
If you allocate memory using malloc inside the merge() function and do not call free(), your program will have a memory leak. Each recursive call allocates memory that never gets released, which can exhaust available heap memory on large inputs.
You can modify the merge step to count how many times an element from the right half is placed before an element from the left half. Each such placement represents one or more inversions. This gives an inversion count in O(n log n) time, far better than the O(n²) brute-force approach.
Merge sort is used in external sorting (sorting data stored on disk), database engines for stable multi-key sorting, standard library implementations, and parallel processing systems where each half can be sorted on a separate thread or processor.
Instead of using mid = (left + right) / 2, always use mid = left + (right - left) / 2. When left and right are both large integers, their sum can exceed the maximum value of an int, causing overflow. The second formula avoids this by computing the difference first.
60 articles published
Rahul Singh is an Associate Content Writer at upGrad, with a strong interest in Data Science, Machine Learning, and Artificial Intelligence. He combines technical development skills with data-driven s...