3.6.2 · D4Sorting & Searching

Exercises — Merge sort — divide and conquer, O(n log n), stable, proof of correctness

2,503 words11 min readBack to topic

Quick reminders (so you never hit an undefined term):

  • = number of elements in the array.
  • comparison = one "is ?" question between two elements.
  • write = placing one element into the output array.
  • stable = equal keys keep their original left-to-right order.
  • merge = the two-pointer routine that fuses two already-sorted lists.

L1 — Recognition

Exercise 1.1

Which single line of the merge routine is responsible for stability, and what would break if you changed it?

Recall Solution

The line if A[i] <= B[j]:. The <= means: on a tie, take the LEFT list's element first. Since the left list holds elements that came earlier in the original array, equal keys stay in original order — that's exactly stability. Change it to < and on a tie you'd take the right element first, swapping equal records → not stable.

Exercise 1.2

Order these three step labels into the correct merge-sort sequence, and say which one does zero comparisons: Combine, Divide, Conquer.

Recall Solution

Correct order: Divide → Conquer → Combine.

  • Divide splits at mid = len//2 — this does zero comparisons, just arithmetic.
  • Conquer recursively sorts each half.
  • Combine = merge, where all the comparisons actually happen.

Exercise 1.3

State merge sort's best, average, and worst time, and its space. One sentence on why best = worst.

Recall Solution

Best = Average = Worst = ; Space (extra array). Why best = worst: the structure never changes with input — merge sort always splits exactly in half and always merges in regardless of whether the input is already sorted, reversed, or random. See Big-O Notation.


L2 — Application

Exercise 2.1

Fully trace merge_sort([8, 3, 5, 1]). Give the split tree and every merge step with the comparison made.

Recall Solution

Refer to the recursion tree in the figure below.

Figure — Merge sort — divide and conquer, O(n log n), stable, proof of correctness

  1. Split [8,3,5,1][8,3] and [5,1] (mid = 4//2 = 2).
  2. [8,3][8],[3]; merge: cmp 8 vs 3 → 3 smaller → [3,8].
  3. [5,1][5],[1]; merge: cmp 5 vs 1 → 1 smaller → [1,5].
  4. Merge [3,8] & [1,5]:
    • cmp 3 vs 1 → take 1[1]
    • cmp 3 vs 5 → take 3[1,3]
    • cmp 8 vs 5 → take 5[1,3,5]
    • right list empty → copy 8[1,3,5,8]

Exercise 2.2

Merge these two sorted lists by hand, listing each comparison: Assume records are tagged 's twos as and 's two as . Show that stability keeps 's twos before 's.

Recall Solution

Using <= (prefer left = on ties):

  • cmp ? yes → take → out
  • cmp ? yes → take → out
  • cmp ? no → take → out
  • cmp ? no → take → out
  • empty → copy … wait, careful: after taking 4, is empty, then copy leftover of = .
  • Final: . All of 's twos () come before 's two () → stability preserved. See Stability of Sorting Algorithms.

Exercise 2.3

For , use the recurrence to state the number of merge layers and the total work per layer.

Recall Solution

Layers to reach size 1: , plus the size-1 base level → total depth levels. Each level does work (level has problems of size , and ). So total , i.e. .


L3 — Analysis

Exercise 3.1

What is the exact maximum number of comparisons to merge two lists whose total length is ? Prove why it's and not .

Recall Solution

Maximum . Proof: every comparison outputs at least one element (the smaller front). After comparisons, at least elements are placed. The loop stops the moment one list empties; at worst that happens right after the second-to-last element is placed, i.e. after comparisons. The final remaining element is copied with no comparison. Hence at most . Worst case is achieved when the two lists interleave perfectly, e.g. , .

Exercise 3.2

Give the exact worst-case comparison count for merging and , and confirm it equals .

Recall Solution

Trace: cmp(1,2)→1; cmp(3,2)→2; cmp(3,4)→3; cmp(5,4)→4; cmp(5,6)→5; then empty, copy 6 (no cmp). That's 5 comparisons, and . ✓ Perfect interleaving forces the maximum.

Exercise 3.3

Merge sort vs insertion sort: for the reverse-sorted input of size , insertion sort does comparisons. Merge sort does . Compute both and give the ratio.

Recall Solution
  • Insertion (worst): .
  • Merge (upper bound): .
  • Ratio . Merge sort does about 51× fewer comparisons here. This gap is the whole point of vs .

L4 — Synthesis

Exercise 4.1

Modify merge sort to count inversions (pairs with ). Explain where in merge the count is incremented, and trace it on .

Recall Solution

During merge, when you take an element from the right list B[j] while the left list A still has elements remaining, every one of those remaining left elements is greater than B[j] (both lists sorted) — so add to the inversion count.

Trace on (true inversions: = 3):

  • Split → and (deeper merges within each half add 0 inversions here since each is already sorted).
  • Merge (left, ) with (right, ):
    • cmp 2 vs 1 → take 1 from right; left has 2 elements remaining → add 2.
    • cmp 2 vs 3 → take 2 from left.
    • cmp 4 vs 3 → take 3 from right; left has 1 element (the 4) remaining → add 1.
    • cmp 4 vs 5 → take 4 from left.
    • right leftover 5 → copy.
  • Total inversions . ✓ Matches the brute-force count.

Exercise 4.2

You have a 100 GB file that does not fit in RAM (8 GB). Explain how the merge primitive lets you sort it, and why the divide step maps onto reading chunks. Which vault topic names this technique?

Recall Solution

This is external sorting — see External Sorting.

  • Divide/Conquer: read the file in chunks that do fit in RAM (say 4 GB each → 25 chunks), sort each chunk in memory, write each back as a sorted "run" on disk.
  • Combine: do a -way merge of the 25 sorted runs. Merge only needs the front of each run in memory at a time — exactly the two-pointer idea generalized to pointers. You stream elements out to the final file, always emitting the smallest current front. Merge sort's key property — that merging needs only sorted inputs, never the whole thing in memory — is precisely what makes it the algorithm of choice for data too big for RAM. (Quicksort, which needs random access, does not adapt as cleanly — see Quick sort.)

L5 — Mastery

Exercise 5.1

Prove, using the loop invariant and strong induction, that merge_sort returns a sorted permutation. Then pinpoint the one step where the inductive hypothesis (IH) is used, and explain what goes wrong if you tried to prove it by weak induction (only assuming correctness for ).

Recall Solution

Merge loop invariant: before each iteration, out is sorted and every element of out is every unconsumed element of both inputs.

  • Init: out=[] — vacuously true.
  • Maintenance: we append . It is everything already in out (invariant) and all remaining (inputs sorted). Both properties survive.
  • Termination: one list empties; the leftover is already sorted and all of out, so out becomes a sorted permutation of . ✓

Strong induction on :

  • Base : trivially sorted, its own permutation. ✓
  • IH: assume correctness for all lengths .
  • Step: split into left of size and right of size , both . The one place the IH is used is here: we assert both recursive calls return sorted permutations — that's licensed by IH because both sizes are strictly less than . Then merge (proven correct above) fuses them.

Why weak induction fails: weak induction only gives you correctness for . But the recursive calls have size , which for is not . You'd have no license to assume the size- calls are correct. Strong induction (all sizes ) is exactly what covers the subproblems. See Recursion and Induction.

Exercise 5.2

Use the Master Theorem to solve and confirm it matches the recursion-tree answer .

Recall Solution

Master Theorem form: with , , . Compute the watershed exponent . Compare with : they're the same orderCase 2. Case 2 gives . ✓ Identical to the recursion-tree result.

Exercise 5.3

A student claims: "If I merge with < instead of <=, the array is still sorted, so the algorithm is still correct." Is the sortedness claim true? Is the algorithm's specification still met? Resolve the apparent contradiction.

Recall Solution
  • Sortedness: ✅ true — with <, ties are still resolved (just favoring the right element), and the output is still non-decreasing. So if the spec is "return a sorted permutation," < is correct.
  • Stability spec: ❌ broken — if the spec additionally requires "equal keys keep original order," then < violates it by taking right-half equals first. Resolution: there's no contradiction — correctness is relative to a specification. < satisfies the weaker (sorted-only) spec but not the stronger (sorted + stable) spec. The parent note's algorithm uses <= precisely to meet the stronger spec.

Connections

  • Merge sort (parent) — definitions and proofs these exercises drill.
  • Master Theorem — used in Exercise 5.2.
  • Recursion and Induction — the strong-induction backbone of L5.
  • External Sorting — Exercise 4.2's real-world payoff.
  • Stability of Sorting Algorithms — Exercises 1.1, 2.2, 5.3.
  • Big-O Notation — the vs comparison.
  • Quick sort — contrast noted in 4.2.