G27
Self-checkedTier 1 12 min readalgo.sorting-merge

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 nlog⁡nn \log n 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 T(n)=2T(n/2)+Θ(n)T(n) = 2T(n/2) + \Theta(n). Its price is Θ(n)\Theta(n) 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 alo,…,ahi−1a_{lo}, \ldots, a_{hi-1}: 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 11 into runs of length 22, these into runs of length 44, and so on, without recursion.

Cost measure. The number of comparisons of two keys (the data movement is Θ(n)\Theta(n) per level, so it has the same order).

How it works

The merge and its invariant. Let ii and jj be the fronts of the left and right run and kk the next free slot of the temporary array. The invariant is: tmp[lo..k−1]\text{tmp}[lo..k-1] holds, in sorted order, the k−lok - lo 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 6,3,8,1,7,2,5,46, 3, 8, 1, 7, 2, 5, 4. 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 run

C source

1#include <stdio.h>
2
3/* merges the sorted runs a[lo..mid-1] and a[mid..hi-1] */
4static void merge(int a[], int tmp[], int lo, int mid, int hi) {
5 int i = lo, j = mid, k = lo;
6 while (i < mid && j < hi) {
7 if (a[j] < a[i]) {
8 tmp[k++] = a[j++];
9 } else {
10 tmp[k++] = a[i++];
11 }
12 }
13 while (i < mid) {
14 tmp[k++] = a[i++];
15 }
16 while (j < hi) {
17 tmp[k++] = a[j++];
18 }
19 for (k = lo; k < hi; k++) {
20 a[k] = tmp[k];
21 }
22}
23
24void merge_sort(int a[], int tmp[], int lo, int hi) {
25 if (hi - lo < 2) {
26 return;
27 }
28 int mid = lo + (hi - lo) / 2;
29 merge_sort(a, tmp, lo, mid);
30 merge_sort(a, tmp, mid, hi);
31 merge(a, tmp, lo, mid, hi);
32}

Array a

6
0
3
1
8
2
1
3
7
4
2
5
5
6
4
7

Temporary array tmp (faded = not part of this merge)

0
1
2
3
4
5
6
7

Counts

comparisons of keys so far = 0

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.

1 / 64
The array 6, 3, 8, 1, 7, 2, 5, 4 is set up by hidden driver code. merge() and merge_sort() are the exact code that runs. Faded cells are outside the range being merged; the lower row is the temporary array. Produced by: real execution: every array, stack, matrix and list in the picture is read from the running program's memory at each step. Apple clang version 21.0.0 (clang-2100.1.1.101). gcc -O0 -o prog prog.c && ./prog

Counting comparisons. Merging runs of sizes pp and qq takes at least min⁡(p,q)\min(p, q) comparisons (one run is used up first, then the rest of the other is copied without comparisons) and at most p+q−1p + q - 1 (the last key is never compared against anything). Moving the keys costs p+qp + q copies. Consequences for n=2kn = 2^k keys, with kk levels of merging:

  • Worst case: every merge takes p+q−1p + q - 1 comparisons, so the total is nn per level minus one per merge: ∑levels(n−number of merges)=kn−(n−1)=nlog⁡2n−n+1\sum_{\text{levels}} (n - \text{number of merges}) = kn - (n - 1) = n \log_2 n - n + 1. For any nn the worst case is W(n)=n⌈log⁡2n⌉−2⌈log⁡2n⌉+1W(n) = n \lceil \log_2 n \rceil - 2^{\lceil \log_2 n \rceil} + 1.
  • Best case (already sorted, or reversed): in each merge one whole run is smaller than the other, so only min⁡(p,q)=n′/2\min(p, q) = n'/2 comparisons are made per merge, n/2n/2 per level: n2log⁡2n\frac{n}{2} \log_2 n.

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     8928

Comparisons of merge sort, measured: start

Computed by a script, not typed
nsortedreversedworst-case inputrandom(n/2) log2 nn 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.

0 / 4
computed by script: the quantities are measured by running C, or evaluated, one row at a time. python3 scripts/gen-algo-sort2-traces.py

Recurrence and time. Dividing costs Θ(1)\Theta(1), merging costs Θ(n)\Theta(n): T(n)=2T(n/2)+Θ(n),T(n) = 2T(n/2) + \Theta(n), and by the Master theorem (case 2) T(n)=Θ(nlog⁡n)T(n) = \Theta(n \log n), 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 n2log⁡2n\frac{n}{2}\log_2 n comparisons).

Space. The array version needs a temporary array of nn keys (Θ(n)\Theta(n) extra space, not in place) and a recursion stack of depth ⌈log⁡2n⌉\lceil \log_2 n \rceil. 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 O(1)O(1) extra nodes plus O(log⁡n)O(\log n) stack (or O(1)O(1) 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 kk sorted lists with nn keys in total, keep the kk front keys in a min-heap (priority queue): each of the nn output keys costs one extraction and one insertion, O(log⁡k)O(\log k), so the time is O(nlog⁡k)O(n \log k). 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 Θ(nlog⁡n)\Theta(n \log n) (divide and conquer applications).

Worked examples

EX 1Merge two runs and count

Easy

Merge 2,5,92, 5, 9 (left) and 1,5,71, 5, 7 (right). Compare 22 and 11: take 11. Compare 22 and 55: take 22. Compare 55 and 55: a tie, take the left 55. Compare 99 and 55: take the right 55. Compare 99 and 77: take 77. The right run is used up: copy 99. Output 1,2,5,5,7,91, 2, 5, 5, 7, 9 after 55 comparisons (the maximum possible is 3+3−1=53 + 3 - 1 = 5, the minimum 33). The left 55 stands before the right 55, so equal keys kept their order.

EX 2Number of comparisons, best and worst

Easy

For n=8n = 8: worst case 8⋅3−8+1=178 \cdot 3 - 8 + 1 = 17, best case 82⋅3=12\frac{8}{2} \cdot 3 = 12. The table gives exactly these for the sorted, reversed and worst-case inputs (12,12,1712, 12, 17). The animation's input 6,3,8,1,7,2,5,46, 3, 8, 1, 7, 2, 5, 4 needs 1717 comparisons (the same as the worst case; check the merge of 1,3,6,81, 3, 6, 8 with 2,4,5,72, 4, 5, 7, which alternates). For n=1000n = 1000 (not a power of two) the worst case is 1000⋅10−1024+1=89771000 \cdot 10 - 1024 + 1 = 8977, while at least ⌈log⁡21000!⌉=8530\lceil \log_2 1000! \rceil = 8530 comparisons are needed by any comparison sort (lower bound): merge sort is within about 5%5\% of the best possible.

EX 3Space and the choice between merge sort and quicksort

Medium

To sort an array of 10610^6 integers by merge sort a second array of 10610^6 integers is needed (44 MB for 4-byte integers) plus about 2020 stack frames. Quicksort needs only O(log⁡n)O(\log n) stack on average. But merge sort guarantees Θ(nlog⁡n)\Theta(n \log n) and is stable, while quicksort can take Θ(n2)\Theta(n^2) and is not stable (quicksort). On a linked list merge sort needs no extra array, so it wins there.

EX 4Merging k sorted lists

Medium

Sorted lists of total length n=106n = 10^6, k=1000k = 1000 lists: a heap of kk front keys makes each output key cost O(log⁡1000)≈10O(\log 1000) \approx 10 comparisons, ≈107\approx 10^7 comparisons in all. Merging them one after another into a growing result would cost Θ(nk)\Theta(nk) in the worst case. Merging them in a balanced way, two at a time (as merge sort does), also costs Θ(nlog⁡k)\Theta(n \log k).

EX 5Recurrences of merge-sort-like algorithms

GATE level

(a) Merge sort on nn keys: T(n)=2T(n/2)+nT(n) = 2T(n/2) + n, Θ(nlog⁡n)\Theta(n \log n). (b) A version that splits into three parts, sorts each and merges them in Θ(n)\Theta(n) per level (three-way merge with a small heap or two comparisons per output key): T(n)=3T(n/3)+n=Θ(nlog⁡n)T(n) = 3T(n/3) + n = \Theta(n \log n), the same order. (c) A "merge sort" that merges by inserting each key of the right run into the left run with Θ(n)\Theta(n) shifting: T(n)=2T(n/2)+n2T(n) = 2T(n/2) + n^2, which is Θ(n2)\Theta(n^2) (root dominates): the merge must be linear for the method to pay off. (d) Minimum comparisons to merge two sorted arrays of nn keys each in the worst case: 2n−12n - 1.

Cheat box

Cheat box

  • Merge two runs of sizes p,qp, q: between min⁡(p,q)\min(p, q) and p+q−1p + q - 1 comparisons, p+qp + q moves.
  • T(n)=2T(n/2)+Θ(n)=Θ(nlog⁡n)T(n) = 2T(n/2) + \Theta(n) = \Theta(n \log n) in best, average and worst case.
  • Worst case comparisons: n⌈log⁡2n⌉−2⌈log⁡2n⌉+1n \lceil \log_2 n \rceil - 2^{\lceil \log_2 n \rceil} + 1 (nlog⁡2n−n+1n \log_2 n - n + 1 for powers of two). Best: n2log⁡2n\frac{n}{2} \log_2 n.
  • Stable (take the left key on a tie). Array version: Θ(n)\Theta(n) extra space, not in place. Linked list: O(1)O(1) extra, stable.
  • Stack depth ⌈log⁡2n⌉\lceil \log_2 n \rceil.
  • kk-way merge with a heap: O(nlog⁡k)O(n \log k). Counting inversions: merge sort with a counter.
  • Basis of external sorting.

Traps and GATE patterns

Connections

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

GATE 2026 · Set 2 · NATQ1 · page 108 of the book
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)
GATE 2016 · Set 1 · MCQQ8 · page 109 of the book
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)
GATE 2012 · MCQQ14 · page 110 of the book
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 )
GATE 2008 · MCQ · 1 markQ16 · page 110 of the book
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)
GATE 2006 · Set 1 · MCQ · 1 markQ26 · page 44 of the book
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 mm keys with a sorted list of nn keys?

Show answer

m+n−1m + n - 1.

Question 2

How many comparisons does merge sort make, at most, on 1616 keys?

Show answer

16⋅4−16+1=4916 \cdot 4 - 16 + 1 = 49 (the table shows 4949 for the worst-case input).

Question 3

Why is merge sort stable?

Show answer

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 nn keys?

Show answer

Θ(nlog⁡n)\Theta(n \log n) time in all cases; Θ(n)\Theta(n) extra space for the temporary array (plus O(log⁡n)O(\log n) stack).

Revision card

One-screen revision

  • Sort halves, merge: T(n)=2T(n/2)+n=Θ(nlog⁡n)T(n) = 2T(n/2) + n = \Theta(n \log n) always.
  • Merge of sizes p,qp, q: min⁡(p,q)\min(p, q) to p+q−1p + q - 1 comparisons.
  • Worst case n⌈lg⁡n⌉−2⌈lg⁡n⌉+1n \lceil \lg n \rceil - 2^{\lceil \lg n \rceil} + 1; best n2lg⁡n\frac{n}{2} \lg n.
  • Stable (left on ties); array version Θ(n)\Theta(n) extra space; linked list O(1)O(1).
  • kk-way merge O(nlog⁡k)O(n \log k); 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