Merge sort
Merge sort: split in halves, sort each, merge the two sorted runs. The merge procedure and its invariant, the exact best and worst case comparison counts (n log2 n - n + 1 in the worst case for n a power of two), Theta(n log n) in every case, why it is stable and needs linear extra space on arrays, bottom-up and linked-list versions, and k-way merging.
Why it exists
Merge sort is the standard answer to "sort with a guaranteed running time and keep equal keys in order". It never degenerates, it is stable, it reads its input sequentially (which is why it is the basis of sorting data on disk and of sorting linked lists), and it is the cleanest example of divide and conquer whose recurrence is . Its price is extra memory when sorting an array.
Prerequisites
You need the divide and conquer pattern and its recurrence (divide and conquer).
Precise definitions
Run. A sorted contiguous piece of an array (or a sorted list).
Merge. Given two sorted runs, produce one sorted run containing all their keys. Keep a pointer at the front of each run, repeatedly compare the two front keys, and move the smaller to the output; when one run is used up, copy the rest of the other.
Merge sort (top-down). To sort : if there are fewer than two keys, stop. Otherwise sort the left half, sort the right half, and merge the two runs.
Bottom-up merge sort. Merge runs of length into runs of length , these into runs of length , and so on, without recursion.
Cost measure. The number of comparisons of two keys (the data movement is per level, so it has the same order).
How it works
The merge and its invariant. Let and be the fronts of the left and right run and the next free slot of the temporary array. The invariant is: holds, in sorted order, the smallest keys of the two runs, and every key still waiting is at least as large as every key in it. Each step moves the smaller front key, so it keeps the invariant. If the two front keys are equal the left one is taken; this single rule makes the sort stable, because equal keys of the left run come from earlier positions.
The code and a real run. The code below is what the animation runs, on . Watch the faded cells: only the range being merged is active, and the lower row is the temporary array.
Merge sort: sort the halves, then merge them through a temporary array
Real runC source
Array a
Temporary array tmp (faded = not part of this merge)
Counts
Blue = the position this step is working on, amber = a position being compared, red = positions just swapped, green = finished or in its final place, a filled blue cell = a value just placed, faded = not part of the structure at this step.
Step 1
Sort 6, 3, 8, 1, 7, 2, 5, 4 with merge sort.
Counting comparisons. Merging runs of sizes and takes at least comparisons (one run is used up first, then the rest of the other is copied without comparisons) and at most (the last key is never compared against anything). Moving the keys costs copies. Consequences for keys, with levels of merging:
- Worst case: every merge takes comparisons, so the total is per level minus one per merge: . For any the worst case is .
- Best case (already sorted, or reversed): in each merge one whole run is smaller than the other, so only comparisons are made per merge, per level: .
The C program below runs merge sort on a sorted, a reversed, a random and a specially built worst-case input (the even-position keys go to the left half and the odd-position keys to the right half, recursively, so that every merge interleaves) and counts comparisons.
#include <stdio.h>
static long cmps;
static void merge(int a[], int tmp[], int lo, int mid, int hi) {
int i = lo, j = mid, k = lo;
while (i < mid && j < hi) {
cmps++;
if (a[j] < a[i]) tmp[k++] = a[j++];
else tmp[k++] = a[i++];
}
while (i < mid) tmp[k++] = a[i++];
while (j < hi) tmp[k++] = a[j++];
for (k = lo; k < hi; k++) a[k] = tmp[k];
}
static void merge_sort(int a[], int tmp[], int lo, int hi) {
if (hi - lo < 2) return;
int mid = lo + (hi - lo) / 2;
merge_sort(a, tmp, lo, mid);
merge_sort(a, tmp, mid, hi);
merge(a, tmp, lo, mid, hi);
}
/* an input on which every merge needs the most comparisons: send the even positions of the sorted order to the left half
and the odd positions to the right half, recursively, so that the two runs of every merge interleave */
static void worst_case(int a[], int tmp[], int n) {
if (n < 2) return;
int h = n / 2;
for (int i = 0; i < n; i++) tmp[i] = a[i];
for (int i = 0; i < h; i++) a[i] = tmp[2 * i];
for (int i = 0; i < n - h; i++) a[h + i] = tmp[2 * i + 1];
worst_case(a, tmp, h);
worst_case(a + h, tmp, n - h);
}
static long run(int a[], int n) {
static int tmp[1024];
cmps = 0;
merge_sort(a, tmp, 0, n);
for (int i = 1; i < n; i++) if (a[i - 1] > a[i]) return -1; /* not sorted: report failure */
return cmps;
}
int main(void) {
static int a[1024], t[1024];
int ns[] = {8, 16, 64, 1024};
unsigned s = 2024;
printf("%5s %8s %9s %8s %8s\n", "n", "sorted", "reversed", "worst", "random");
for (int q = 0; q < 4; q++) {
int n = ns[q];
for (int i = 0; i < n; i++) a[i] = i;
long c1 = run(a, n);
for (int i = 0; i < n; i++) a[i] = n - i;
long c2 = run(a, n);
for (int i = 0; i < n; i++) a[i] = i;
worst_case(a, t, n);
long c3 = run(a, n);
for (int i = 0; i < n; i++) { s = s * 1103515245u + 12345u; a[i] = (int)((s >> 8) % 100000); }
long c4 = run(a, n);
printf("%5d %8ld %9ld %8ld %8ld\n", n, c1, c2, c3, c4);
}
return 0;
} n sorted reversed worst random
8 12 12 17 15
16 32 32 49 46
64 192 192 321 307
1024 5120 5120 9217 8928Comparisons of merge sort, measured: start
Computed by a script, not typed| n | sorted | reversed | worst-case input | random | (n/2) log2 n | n log2 n - n + 1 |
|---|---|---|---|---|---|---|
| 8 | ||||||
| 16 | ||||||
| 64 | ||||||
| 1024 |
Step 0
Merge sort was run on four kinds of input of n = 8, 16, 64, 1024 keys, counting comparisons of keys. The program is on this page.
Recurrence and time. Dividing costs , merging costs : and by the Master theorem (case 2) , in the best, average and worst case alike: merge sort does not get faster on sorted input beyond a constant factor (the best case is still comparisons).
Space. The array version needs a temporary array of keys ( extra space, not in place) and a recursion stack of depth . A merge of two runs in the array itself, without the temporary array, exists but is complicated and slower. The linked-list version needs no temporary array at all: merging relinks the nodes, giving extra nodes plus stack (or for the bottom-up version), and it stays stable. This is why merge sort is the method of choice for linked lists.
Stability. Stable, by the tie rule above. (An implementation that takes the right key on a tie is correct but not stable.)
Merging many runs. To merge sorted lists with keys in total, keep the front keys in a min-heap (priority queue): each of the output keys costs one extraction and one insertion, , so the time is . External sorting uses this: sort pieces that fit in memory, then merge them in few passes.
Inversions and other uses. Counting how many times a key from the right run is taken before keys of the left run counts the inversions of the input in (divide and conquer applications).
Worked examples
EX 1Merge two runs and count
EasyMerge (left) and (right). Compare and : take . Compare and : take . Compare and : a tie, take the left . Compare and : take the right . Compare and : take . The right run is used up: copy . Output after comparisons (the maximum possible is , the minimum ). The left stands before the right , so equal keys kept their order.
EX 2Number of comparisons, best and worst
EasyFor : worst case , best case . The table gives exactly these for the sorted, reversed and worst-case inputs (). The animation's input needs comparisons (the same as the worst case; check the merge of with , which alternates). For (not a power of two) the worst case is , while at least comparisons are needed by any comparison sort (lower bound): merge sort is within about of the best possible.
EX 3Space and the choice between merge sort and quicksort
MediumTo sort an array of integers by merge sort a second array of integers is needed ( MB for 4-byte integers) plus about stack frames. Quicksort needs only stack on average. But merge sort guarantees and is stable, while quicksort can take and is not stable (quicksort). On a linked list merge sort needs no extra array, so it wins there.
EX 4Merging k sorted lists
MediumSorted lists of total length , lists: a heap of front keys makes each output key cost comparisons, comparisons in all. Merging them one after another into a growing result would cost in the worst case. Merging them in a balanced way, two at a time (as merge sort does), also costs .
EX 5Recurrences of merge-sort-like algorithms
GATE level(a) Merge sort on keys: , . (b) A version that splits into three parts, sorts each and merges them in per level (three-way merge with a small heap or two comparisons per output key): , the same order. (c) A "merge sort" that merges by inserting each key of the right run into the left run with shifting: , which is (root dominates): the merge must be linear for the method to pay off. (d) Minimum comparisons to merge two sorted arrays of keys each in the worst case: .
Cheat box
Cheat box
- Merge two runs of sizes : between and comparisons, moves.
- in best, average and worst case.
- Worst case comparisons: ( for powers of two). Best: .
- Stable (take the left key on a tie). Array version: extra space, not in place. Linked list: extra, stable.
- Stack depth .
- -way merge with a heap: . Counting inversions: merge sort with a counter.
- Basis of external sorting.
Traps and GATE patterns
Connections
Builds on
Unlocks
Across subjects
No cross-subject links yet.
Merge sort is the standard example of divide and conquer; its recurrence is solved in solving recurrences. It is compared with quicksort and heap sort in stability and comparison of sorts, and its comparison count is close to the information-theoretic minimum of the lower bound. Counting inversions during the merge is in divide and conquer applications.
PYQs
5 previous year questions from your book. I re-solved each one myself (2 by running or simulating, 3 by reasoning only); the book's key is shown next to my answer. All PYQs
Consider an array A = [10, 7, 8, 19, 41,35, 25, 31]. Suppose the merge sort algorithm is executed on array A to sort it in increasing order. The merge sort algorithm will carry out a total of 7 merge operations. A merge operation on sorted left array L and sorted right array R is said to be void if the output of the merge operation is the elements of array L followed by the elements of array R. The number of void merge operations among these 7 merge operations is . (answer in integer)
The worst-case running time of Insertion sort, Merge sort and Quick sort, respectively, are:
- (a)θ(nlogn), θ(nlogn) and θ(n2)
- (b)θ(n2) , θ(n2) and θ(nlogn)
- (c)θ(n2), θ(nlogn) and θ(nlogn)
- (d)θ(n2), θ(nlogn) and θ(n2)
A list of n strings, each of length n, is sorted into lexicographic order using the merge-sort algorithm. The worst case running time of this computation is
- (a)O (n log n)
- (b)O (n2 log n)
- (c)O (n2 + log n)
- (d)O (n2 )
The average case and worst case complexities for Merge sort algorithm are
- (a)O(n log n),O(n2)
- (b)O(n2), O(nlog2 n)
- (c)O(n2logn) ,O(n2)
- (d)O(nlog2n) , O(nlog2 n)
Consider the following C-function in which a[n] and
b[m] are two sorted integer arrays and c[n+m] be
another integer array.
void xyz(int a[], int b[], int c[])
{
int i, j, k;
i = j = k = 0;
while ((i < n) && (j < m))
if (a[i] < b[j])
c[k++] = a[i++];
else
c[k++] = b[j++];
}
Which of the following condition(s) hold(s) after the
termination of the while loop?
(i) j<m, k=n+j-1, and a[n-1]<b[j] if i=n
(ii) i<n, k=m+i-1, and b[m-1]≤a[i] if j=m- (a)only (i)
- (b)only (ii)
- (c)either (i) or (ii) but not both
- (d)neither (i) nor (ii)
Self-check
Question 1
What is the maximum number of comparisons needed to merge a sorted list of keys with a sorted list of keys?
Show answerHide
.
Question 2
How many comparisons does merge sort make, at most, on keys?
Show answerHide
(the table shows for the worst-case input).
Question 3
Why is merge sort stable?
Show answerHide
When the two front keys of the runs are equal the merge takes the one from the left run, which held the earlier positions, so equal keys never change their relative order.
Question 4
What are the time and extra space of merge sort on an array of keys?
Show answerHide
time in all cases; extra space for the temporary array (plus stack).
Revision card
One-screen revision
- Sort halves, merge: always.
- Merge of sizes : to comparisons.
- Worst case ; best .
- Stable (left on ties); array version extra space; linked list .
- -way merge ; basis of external sorting.
References
- ·Cormen, Leiserson, Rivest, Stein, Introduction to Algorithms (3rd edition), Section 2.3 Designing algorithms (merge sort) and Chapter 4
- ·Sedgewick and Wayne, Algorithms (4th edition), Section 2.2 Mergesort
- ·Knuth, The Art of Computer Programming, Volume 3, Section 5.2.4 Sorting by merging
Verification
Merge sort was re-implemented in Python and run on EVERY permutation of up to 9 keys: the worst case equals W(n) = W(floor(n/2)) + W(ceil(n/2)) + n - 1 and the closed form n ceil(lg n) - 2^ceil(lg n) + 1 (checked for every n up to 2000), the best case equals its own recurrence, and the sort is stable on 2000 random inputs with duplicates. The interleaving input of the page attains the worst case for n = 2 to 1024. The C program on this page is the one that produced the table, and the animation is a real run of the code shown. The k-way merge cost and the linked-list remarks are standard results quoted without a separate experiment. Textbook chapter references are from memory. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand or by a small script (loop counts, recurrences, merge and quicksort counts and averages, hash probes and load-factor formulas, DP tables, MST and shortest-path runs, Floyd matrices); long C programs were not re-read line by line (they are compiled and compared by npm run verify:c, and their printed outputs were checked against the prose); tables and animations are machine output and were read, not re-run; No other defect found. Status raised to self-checked; verified needs a textbook or human check.
last verified: never
My notes (saved in this browser)