Chapter 18: Efficient and Specialized Sorting
18.01Beginner / Intermediate6 topics22 min2 interactive animations

Merge sort

Merge sort splits the array in half, sorts each half recursively, and merges the two sorted halves. It guarantees O(n log n) time for every input and is stable, at the price of O(n) extra memory.

Learning goals

  • Trace the recursion tree and the merge step of top-down merge sort
  • Write a stable merge that uses one reusable buffer
  • Convert the recursion into the bottom-up version
  • Sort a linked list with merge sort in O(1) extra space

Prerequisites

RecursionInsertion sortTwo-pointer techniqueBig-O notation

Merging two sorted piles of exam papers is easy: keep comparing the top papers and take the lower one. Merge sort sorts a big pile by sorting two halves first, then doing that cheap merge.

18.01.1

Divide and conquer

Divide: split arr[lo..hi] at mid. Conquer: sort both halves recursively. Combine: merge the two sorted halves. A single element is already sorted, which is the base case.

The recursion tree has about log₂ n levels, and the merges on each level touch every element once. That gives n work per level and O(n log n) in total, regardless of the input order. Step through the animation and watch the call stack, the tmp[] buffer and the sorted runs grow.

Best

O(n log n)

Average

O(n log n)

Worst

O(n log n)

Space

O(n)

Merge sort (top-down)

Interactive · edit the input

Your input

Try

int[] arr · length 8

38
27
43
3
9
82
10
15
01234567
Being comparedSorted runOutside this call
Setup

Divide the 8 elements until single elements remain, then merge sorted runs back together.

Step 1 / 94
Java
1public static void mergeSort(int[] arr, int lo, int hi) {
2 if (hi - lo < 1) return;
3 int mid = lo + (hi - lo) / 2;
4 mergeSort(arr, lo, mid);
5 mergeSort(arr, mid + 1, hi);
6 merge(arr, lo, mid, hi);
7}
8
9static void merge(int[] arr, int lo, int mid, int hi) {
10 int[] tmp = new int[hi - lo + 1];
11 int i = lo, j = mid + 1, k = 0;
12 while (i <= mid && j <= hi) {
13 if (arr[i] <= arr[j]) tmp[k++] = arr[i++];
14 else tmp[k++] = arr[j++];
15 }
16 while (i <= mid) tmp[k++] = arr[i++];
17 while (j <= hi) tmp[k++] = arr[j++];
18 System.arraycopy(tmp, 0, arr, lo, tmp.length);
19}

Live state

0 comparisons

n

8

No condition evaluated on this step
Execution trace (dry run table)Show 94 steps
StepLineStateWhat happens
1L1n=8Divide the 8 elements until single elements remain, then merge sorted runs back together.
2L1lo=0 hi=7 size=8Enter mergeSort(arr, 0, 7) on 8 elements.
3L2lo=0 hi=7More than one element, so split in half.
4L3lo=0 mid=3 hi=7mid = 3. Left half [0..3], right half [4..7].
5L4lo=0 hi=3 size=4Enter mergeSort(arr, 0, 3) on 4 elements.
6L2lo=0 hi=3More than one element, so split in half.
7L3lo=0 mid=1 hi=3mid = 1. Left half [0..1], right half [2..3].
8L4lo=0 hi=1 size=2Enter mergeSort(arr, 0, 1) on 2 elements.
9L2lo=0 hi=1More than one element, so split in half.
10L3lo=0 mid=0 hi=1mid = 0. Left half [0..0], right half [1..1].
11L4lo=0 hi=0 size=1Enter mergeSort(arr, 0, 0) on 1 element.
12L2lo=0 hi=0Base case: one element is already sorted.
13L5lo=1 hi=1 size=1Enter mergeSort(arr, 1, 1) on 1 element.
14L2lo=1 hi=1Base case: one element is already sorted.
15L10lo=0 mid=0 hi=1 i=0 j=1 k=0Allocate tmp for 2 elements. Left run [0..0] and right run [1..1] are each already sorted.
16L13lo=0 mid=0 hi=1 i=0 j=1 k=0The right head is strictly smaller, so take it.
17L14lo=0 mid=0 hi=1 i=0 j=2 k=1tmp[0] = 27.
18L16lo=0 mid=0 hi=1 i=1 j=2 k=2The left run still has 1 element. They are already sorted and no larger run remains, so copy them all.
19L18lo=0 mid=0 hi=1 i=1 j=2 k=2Copy tmp back into arr[0..1]. That range is now sorted.
20L5lo=2 hi=3 size=2Enter mergeSort(arr, 2, 3) on 2 elements.
21L2lo=2 hi=3More than one element, so split in half.
22L3lo=2 mid=2 hi=3mid = 2. Left half [2..2], right half [3..3].
23L4lo=2 hi=2 size=1Enter mergeSort(arr, 2, 2) on 1 element.
24L2lo=2 hi=2Base case: one element is already sorted.
25L5lo=3 hi=3 size=1Enter mergeSort(arr, 3, 3) on 1 element.
26L2lo=3 hi=3Base case: one element is already sorted.
27L10lo=2 mid=2 hi=3 i=2 j=3 k=0Allocate tmp for 2 elements. Left run [2..2] and right run [3..3] are each already sorted.
28L13lo=2 mid=2 hi=3 i=2 j=3 k=0The right head is strictly smaller, so take it.
29L14lo=2 mid=2 hi=3 i=2 j=4 k=1tmp[0] = 3.
30L16lo=2 mid=2 hi=3 i=3 j=4 k=2The left run still has 1 element. They are already sorted and no larger run remains, so copy them all.
31L18lo=2 mid=2 hi=3 i=3 j=4 k=2Copy tmp back into arr[2..3]. That range is now sorted.
32L10lo=0 mid=1 hi=3 i=0 j=2 k=0Allocate tmp for 4 elements. Left run [0..1] and right run [2..3] are each already sorted.
33L13lo=0 mid=1 hi=3 i=0 j=2 k=0The right head is strictly smaller, so take it.
34L14lo=0 mid=1 hi=3 i=0 j=3 k=1tmp[0] = 3.
35L13lo=0 mid=1 hi=3 i=0 j=3 k=1The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
36L13lo=0 mid=1 hi=3 i=1 j=3 k=2tmp[1] = 27.
37L13lo=0 mid=1 hi=3 i=1 j=3 k=2The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
38L13lo=0 mid=1 hi=3 i=2 j=3 k=3tmp[2] = 38.
39L17lo=0 mid=1 hi=3 i=2 j=4 k=4The right run still has 1 element. They are already sorted and no larger run remains, so copy them all.
40L18lo=0 mid=1 hi=3 i=2 j=4 k=4Copy tmp back into arr[0..3]. That range is now sorted.
41L5lo=4 hi=7 size=4Enter mergeSort(arr, 4, 7) on 4 elements.
42L2lo=4 hi=7More than one element, so split in half.
43L3lo=4 mid=5 hi=7mid = 5. Left half [4..5], right half [6..7].
44L4lo=4 hi=5 size=2Enter mergeSort(arr, 4, 5) on 2 elements.
45L2lo=4 hi=5More than one element, so split in half.
46L3lo=4 mid=4 hi=5mid = 4. Left half [4..4], right half [5..5].
47L4lo=4 hi=4 size=1Enter mergeSort(arr, 4, 4) on 1 element.
48L2lo=4 hi=4Base case: one element is already sorted.
49L5lo=5 hi=5 size=1Enter mergeSort(arr, 5, 5) on 1 element.
50L2lo=5 hi=5Base case: one element is already sorted.
51L10lo=4 mid=4 hi=5 i=4 j=5 k=0Allocate tmp for 2 elements. Left run [4..4] and right run [5..5] are each already sorted.
52L13lo=4 mid=4 hi=5 i=4 j=5 k=0The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
53L13lo=4 mid=4 hi=5 i=5 j=5 k=1tmp[0] = 9.
54L17lo=4 mid=4 hi=5 i=5 j=6 k=2The right run still has 1 element. They are already sorted and no larger run remains, so copy them all.
55L18lo=4 mid=4 hi=5 i=5 j=6 k=2Copy tmp back into arr[4..5]. That range is now sorted.
56L5lo=6 hi=7 size=2Enter mergeSort(arr, 6, 7) on 2 elements.
57L2lo=6 hi=7More than one element, so split in half.
58L3lo=6 mid=6 hi=7mid = 6. Left half [6..6], right half [7..7].
59L4lo=6 hi=6 size=1Enter mergeSort(arr, 6, 6) on 1 element.
60L2lo=6 hi=6Base case: one element is already sorted.
61L5lo=7 hi=7 size=1Enter mergeSort(arr, 7, 7) on 1 element.
62L2lo=7 hi=7Base case: one element is already sorted.
63L10lo=6 mid=6 hi=7 i=6 j=7 k=0Allocate tmp for 2 elements. Left run [6..6] and right run [7..7] are each already sorted.
64L13lo=6 mid=6 hi=7 i=6 j=7 k=0The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
65L13lo=6 mid=6 hi=7 i=7 j=7 k=1tmp[0] = 10.
66L17lo=6 mid=6 hi=7 i=7 j=8 k=2The right run still has 1 element. They are already sorted and no larger run remains, so copy them all.
67L18lo=6 mid=6 hi=7 i=7 j=8 k=2Copy tmp back into arr[6..7]. That range is now sorted.
68L10lo=4 mid=5 hi=7 i=4 j=6 k=0Allocate tmp for 4 elements. Left run [4..5] and right run [6..7] are each already sorted.
69L13lo=4 mid=5 hi=7 i=4 j=6 k=0The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
70L13lo=4 mid=5 hi=7 i=5 j=6 k=1tmp[0] = 9.
71L13lo=4 mid=5 hi=7 i=5 j=6 k=1The right head is strictly smaller, so take it.
72L14lo=4 mid=5 hi=7 i=5 j=7 k=2tmp[1] = 10.
73L13lo=4 mid=5 hi=7 i=5 j=7 k=2The right head is strictly smaller, so take it.
74L14lo=4 mid=5 hi=7 i=5 j=8 k=3tmp[2] = 15.
75L16lo=4 mid=5 hi=7 i=6 j=8 k=4The left run still has 1 element. They are already sorted and no larger run remains, so copy them all.
76L18lo=4 mid=5 hi=7 i=6 j=8 k=4Copy tmp back into arr[4..7]. That range is now sorted.
77L10lo=0 mid=3 hi=7 i=0 j=4 k=0Allocate tmp for 8 elements. Left run [0..3] and right run [4..7] are each already sorted.
78L13lo=0 mid=3 hi=7 i=0 j=4 k=0The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
79L13lo=0 mid=3 hi=7 i=1 j=4 k=1tmp[0] = 3.
80L13lo=0 mid=3 hi=7 i=1 j=4 k=1The right head is strictly smaller, so take it.
81L14lo=0 mid=3 hi=7 i=1 j=5 k=2tmp[1] = 9.
82L13lo=0 mid=3 hi=7 i=1 j=5 k=2The right head is strictly smaller, so take it.
83L14lo=0 mid=3 hi=7 i=1 j=6 k=3tmp[2] = 10.
84L13lo=0 mid=3 hi=7 i=1 j=6 k=3The right head is strictly smaller, so take it.
85L14lo=0 mid=3 hi=7 i=1 j=7 k=4tmp[3] = 15.
86L13lo=0 mid=3 hi=7 i=1 j=7 k=4The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
87L13lo=0 mid=3 hi=7 i=2 j=7 k=5tmp[4] = 27.
88L13lo=0 mid=3 hi=7 i=2 j=7 k=5The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
89L13lo=0 mid=3 hi=7 i=3 j=7 k=6tmp[5] = 38.
90L13lo=0 mid=3 hi=7 i=3 j=7 k=6The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
91L13lo=0 mid=3 hi=7 i=4 j=7 k=7tmp[6] = 43.
92L17lo=0 mid=3 hi=7 i=4 j=8 k=8The right run still has 1 element. They are already sorted and no larger run remains, so copy them all.
93L18lo=0 mid=3 hi=7 i=4 j=8 k=8Copy tmp back into arr[0..7]. That range is now sorted.
94L6Sorted with 17 comparisons. About n log n comparisons, whatever the input order.
18.01.2

Merge procedure

Merging keeps one pointer at the head of each sorted run, i and j. Compare the two heads, copy the smaller into tmp, and advance that pointer. When one run runs out, copy the remainder of the other, since it is already sorted.

Merging two runs of sizes a and b takes at most a + b - 1 comparisons and exactly a + b writes. That linear cost is what makes the whole algorithm O(n log n).

For n = 8 the worst case is n⌈log₂ n⌉ - 2^⌈log₂ n⌉ + 1 = 17 comparisons. The default animation input reaches exactly that.

StepLeft run headRight run headAction
1393 <= 9, take 3
227927 > 9, take 9
3271027 > 10, take 10
4271527 > 15, take 15
527(empty)right run empty, copy 27, 38, 43
18.01.3

Stable sorting

Merge sort is stable if, on ties, the element from the left run is taken first. That is the <= in arr[i] <= arr[j]. Elements from the left run came earlier in the input, so equal keys keep their original order.

Writing < there still sorts correctly but silently destroys stability. Run the “Duplicates” preset and check that the a/b tags stay in order.

18.01.4

Temporary arrays

Allocating a new tmp array inside every merge creates O(n) garbage per level. Allocate one buffer of size n up front and reuse it in every merge call. Space stays O(n), plus O(log n) recursion stack.

Two further optimisations are worth knowing. If arr[mid] <= arr[mid + 1] the halves are already in order, so skip the merge (this makes already sorted input O(n)). And for small ranges, insertion sort is faster than recursing.

Java
1public static void mergeSort(int[] arr) {
2 int[] buffer = new int[arr.length]; // allocated once, reused by every merge
3 sort(arr, buffer, 0, arr.length - 1);
4}
5
6private static void sort(int[] arr, int[] buf, int lo, int hi) {
7 if (lo >= hi) return;
8 int mid = lo + (hi - lo) / 2;
9 sort(arr, buf, lo, mid);
10 sort(arr, buf, mid + 1, hi);
11 if (arr[mid] <= arr[mid + 1]) return; // already in order: skip the merge
12 merge(arr, buf, lo, mid, hi);
13}
14
15private static void merge(int[] arr, int[] buf, int lo, int mid, int hi) {
16 System.arraycopy(arr, lo, buf, lo, hi - lo + 1);
17 int i = lo, j = mid + 1;
18 for (int k = lo; k <= hi; k++) {
19 if (i > mid) arr[k] = buf[j++];
20 else if (j > hi) arr[k] = buf[i++];
21 else if (buf[j] < buf[i]) arr[k] = buf[j++]; // strict <: ties take the left element
22 else arr[k] = buf[i++];
23 }
24}
18.01.5

Bottom-up merge sort

Bottom-up merge sort removes the recursion. Treat the array as n runs of width 1, merge neighbouring pairs into runs of width 2, then 4, then 8, and so on until one run remains.

It performs the same merges as the top-down version when n is a power of two, uses no call stack, and is a natural fit for sorting data that arrives in runs. The last run of a round may be shorter, so clamp hi to n - 1.

Best

O(n log n)

Average

O(n log n)

Worst

O(n log n)

Space

O(n)

Merge sort (bottom-up)

Interactive · edit the input

Your input

Try

int[] arr · length 8

38
27
43
3
9
82
10
15
01234567
Being comparedMerged runNot in this merge
Setup

No recursion: start with runs of width 1 and merge neighbouring pairs, doubling the width each round.

Step 1 / 67
Java
1public static void mergeSortBottomUp(int[] arr) {
2 int n = arr.length;
3 for (int width = 1; width < n; width *= 2) {
4 for (int lo = 0; lo < n - width; lo += 2 * width) {
5 int mid = lo + width - 1;
6 int hi = Math.min(lo + 2 * width - 1, n - 1);
7 merge(arr, lo, mid, hi);
8 }
9 }
10}
11
12static void merge(int[] arr, int lo, int mid, int hi) {
13 int[] tmp = new int[hi - lo + 1];
14 int i = lo, j = mid + 1, k = 0;
15 while (i <= mid && j <= hi) {
16 if (arr[i] <= arr[j]) tmp[k++] = arr[i++];
17 else tmp[k++] = arr[j++];
18 }
19 while (i <= mid) tmp[k++] = arr[i++];
20 while (j <= hi) tmp[k++] = arr[j++];
21 System.arraycopy(tmp, 0, arr, lo, tmp.length);
22}

Live state

0 comparisons

n

8

No condition evaluated on this step
Execution trace (dry run table)Show 67 steps
StepLineStateWhat happens
1L2n=8No recursion: start with runs of width 1 and merge neighbouring pairs, doubling the width each round.
2L3width=1Width 1: merge adjacent runs of 1 element.
3L6width=1 lo=0 mid=0 hi=1Merge [0..0] with [1..1].
4L13lo=0 mid=0 hi=1 i=0 j=1 k=0Allocate tmp for 2 elements. Left run [0..0] and right run [1..1] are each already sorted.
5L16lo=0 mid=0 hi=1 i=0 j=1 k=0The right head is strictly smaller, so take it.
6L17lo=0 mid=0 hi=1 i=0 j=2 k=1tmp[0] = 27.
7L19lo=0 mid=0 hi=1 i=1 j=2 k=2The left run still has 1 element. They are already sorted and no larger run remains, so copy them all.
8L21lo=0 mid=0 hi=1 i=1 j=2 k=2Copy tmp back into arr[0..1]. That range is now sorted.
9L6width=1 lo=2 mid=2 hi=3Merge [2..2] with [3..3].
10L13lo=2 mid=2 hi=3 i=2 j=3 k=0Allocate tmp for 2 elements. Left run [2..2] and right run [3..3] are each already sorted.
11L16lo=2 mid=2 hi=3 i=2 j=3 k=0The right head is strictly smaller, so take it.
12L17lo=2 mid=2 hi=3 i=2 j=4 k=1tmp[0] = 3.
13L19lo=2 mid=2 hi=3 i=3 j=4 k=2The left run still has 1 element. They are already sorted and no larger run remains, so copy them all.
14L21lo=2 mid=2 hi=3 i=3 j=4 k=2Copy tmp back into arr[2..3]. That range is now sorted.
15L6width=1 lo=4 mid=4 hi=5Merge [4..4] with [5..5].
16L13lo=4 mid=4 hi=5 i=4 j=5 k=0Allocate tmp for 2 elements. Left run [4..4] and right run [5..5] are each already sorted.
17L16lo=4 mid=4 hi=5 i=4 j=5 k=0The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
18L16lo=4 mid=4 hi=5 i=5 j=5 k=1tmp[0] = 9.
19L20lo=4 mid=4 hi=5 i=5 j=6 k=2The right run still has 1 element. They are already sorted and no larger run remains, so copy them all.
20L21lo=4 mid=4 hi=5 i=5 j=6 k=2Copy tmp back into arr[4..5]. That range is now sorted.
21L6width=1 lo=6 mid=6 hi=7Merge [6..6] with [7..7].
22L13lo=6 mid=6 hi=7 i=6 j=7 k=0Allocate tmp for 2 elements. Left run [6..6] and right run [7..7] are each already sorted.
23L16lo=6 mid=6 hi=7 i=6 j=7 k=0The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
24L16lo=6 mid=6 hi=7 i=7 j=7 k=1tmp[0] = 10.
25L20lo=6 mid=6 hi=7 i=7 j=8 k=2The right run still has 1 element. They are already sorted and no larger run remains, so copy them all.
26L21lo=6 mid=6 hi=7 i=7 j=8 k=2Copy tmp back into arr[6..7]. That range is now sorted.
27L3width=2Width 2: merge adjacent runs of 2 elements.
28L6width=2 lo=0 mid=1 hi=3Merge [0..1] with [2..3].
29L13lo=0 mid=1 hi=3 i=0 j=2 k=0Allocate tmp for 4 elements. Left run [0..1] and right run [2..3] are each already sorted.
30L16lo=0 mid=1 hi=3 i=0 j=2 k=0The right head is strictly smaller, so take it.
31L17lo=0 mid=1 hi=3 i=0 j=3 k=1tmp[0] = 3.
32L16lo=0 mid=1 hi=3 i=0 j=3 k=1The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
33L16lo=0 mid=1 hi=3 i=1 j=3 k=2tmp[1] = 27.
34L16lo=0 mid=1 hi=3 i=1 j=3 k=2The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
35L16lo=0 mid=1 hi=3 i=2 j=3 k=3tmp[2] = 38.
36L20lo=0 mid=1 hi=3 i=2 j=4 k=4The right run still has 1 element. They are already sorted and no larger run remains, so copy them all.
37L21lo=0 mid=1 hi=3 i=2 j=4 k=4Copy tmp back into arr[0..3]. That range is now sorted.
38L6width=2 lo=4 mid=5 hi=7Merge [4..5] with [6..7].
39L13lo=4 mid=5 hi=7 i=4 j=6 k=0Allocate tmp for 4 elements. Left run [4..5] and right run [6..7] are each already sorted.
40L16lo=4 mid=5 hi=7 i=4 j=6 k=0The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
41L16lo=4 mid=5 hi=7 i=5 j=6 k=1tmp[0] = 9.
42L16lo=4 mid=5 hi=7 i=5 j=6 k=1The right head is strictly smaller, so take it.
43L17lo=4 mid=5 hi=7 i=5 j=7 k=2tmp[1] = 10.
44L16lo=4 mid=5 hi=7 i=5 j=7 k=2The right head is strictly smaller, so take it.
45L17lo=4 mid=5 hi=7 i=5 j=8 k=3tmp[2] = 15.
46L19lo=4 mid=5 hi=7 i=6 j=8 k=4The left run still has 1 element. They are already sorted and no larger run remains, so copy them all.
47L21lo=4 mid=5 hi=7 i=6 j=8 k=4Copy tmp back into arr[4..7]. That range is now sorted.
48L3width=4Width 4: merge adjacent runs of 4 elements.
49L6width=4 lo=0 mid=3 hi=7Merge [0..3] with [4..7].
50L13lo=0 mid=3 hi=7 i=0 j=4 k=0Allocate tmp for 8 elements. Left run [0..3] and right run [4..7] are each already sorted.
51L16lo=0 mid=3 hi=7 i=0 j=4 k=0The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
52L16lo=0 mid=3 hi=7 i=1 j=4 k=1tmp[0] = 3.
53L16lo=0 mid=3 hi=7 i=1 j=4 k=1The right head is strictly smaller, so take it.
54L17lo=0 mid=3 hi=7 i=1 j=5 k=2tmp[1] = 9.
55L16lo=0 mid=3 hi=7 i=1 j=5 k=2The right head is strictly smaller, so take it.
56L17lo=0 mid=3 hi=7 i=1 j=6 k=3tmp[2] = 10.
57L16lo=0 mid=3 hi=7 i=1 j=6 k=3The right head is strictly smaller, so take it.
58L17lo=0 mid=3 hi=7 i=1 j=7 k=4tmp[3] = 15.
59L16lo=0 mid=3 hi=7 i=1 j=7 k=4The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
60L16lo=0 mid=3 hi=7 i=2 j=7 k=5tmp[4] = 27.
61L16lo=0 mid=3 hi=7 i=2 j=7 k=5The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
62L16lo=0 mid=3 hi=7 i=3 j=7 k=6tmp[5] = 38.
63L16lo=0 mid=3 hi=7 i=3 j=7 k=6The left head is not larger, so take it. Using <= (left wins ties) is what makes merge sort stable.
64L16lo=0 mid=3 hi=7 i=4 j=7 k=7tmp[6] = 43.
65L20lo=0 mid=3 hi=7 i=4 j=8 k=8The right run still has 1 element. They are already sorted and no larger run remains, so copy them all.
66L21lo=0 mid=3 hi=7 i=4 j=8 k=8Copy tmp back into arr[0..7]. That range is now sorted.
67L10Sorted with 17 comparisons in 3 rounds.
18.01.6

Linked list merge sort

Merge sort is the standard way to sort a linked list. Arrays make splitting free but merging needs a buffer; lists are the opposite: finding the middle costs O(n) (slow and fast pointers), but merging just relinks nodes, so no extra buffer is needed.

Quick sort and heap sort depend on random access, which lists do not have, so merge sort wins here. Extra space is only the O(log n) recursion stack.

Java
1static ListNode sortList(ListNode head) {
2 if (head == null || head.next == null) return head;
3 ListNode slow = head, fast = head.next; // find the middle
4 while (fast != null && fast.next != null) {
5 slow = slow.next;
6 fast = fast.next.next;
7 }
8 ListNode right = slow.next;
9 slow.next = null; // cut the list in two
10 return merge(sortList(head), sortList(right));
11}
12
13static ListNode merge(ListNode a, ListNode b) {
14 ListNode dummy = new ListNode(0), tail = dummy;
15 while (a != null && b != null) {
16 if (b.val < a.val) { tail.next = b; b = b.next; } // ties keep the left node
17 else { tail.next = a; a = a.next; }
18 tail = tail.next;
19 }
20 tail.next = (a != null) ? a : b;
21 return dummy.next;
22}

Worst

O(n log n)

Space

O(log n) stack

Practice ladder

Now try it yourself

Easy

  • Merge two sorted arrays into a new array
  • Merge sorted array (merge nums2 into nums1 from the back)
  • Check whether an array is sorted in O(n)

Medium

  • Sort a linked list in O(n log n)
  • Merge k sorted lists
  • Sort an array of strings by length, stably

Advanced

  • Count inversions during the merge
  • In-place merge in O(1) extra space and discuss its cost
  • Natural merge sort that exploits existing runs

Key takeaways

  • Merge sort is O(n log n) for every input, stable, and needs O(n) extra space for arrays.
  • Take from the left run on ties to stay stable; reuse one buffer instead of allocating per merge.
  • Bottom-up avoids recursion; on linked lists merge sort needs no buffer at all.