Two algorithms in pseudocode
Two algorithms, one idea: split in half, solve the halves, put them back together. Recursion is familiar from lesson 5 — there it was a traversal, here it is a sort.
They differ in where the work happens: merge sort does it on the way back up, quicksort on the way down.
Merge sort
MergeSort(items):
if len(items) <= 1: return a copy
mid ← len(items) / 2
left ← MergeSort(items[:mid])
right ← MergeSort(items[mid:])
return Merge(left, right)
Merge(a, b):
out ← empty, capacity len(a)+len(b)
i ← 0; j ← 0
while i < len(a) and j < len(b):
cmp.Hit()
if a[i].Title <= b[j].Title:
out ← out + a[i]; i ← i + 1
else:
out ← out + b[j]; j ← j + 1
moves.Hit()
append what is left of a, then of b (each a moves.Hit())
return out
The splitting compares nothing. All the work is in Merge, and it is linear:
every element is touched once. There are log₂ n levels and n work at each — which
is where O(n log n) comes from.
One character, and stability lives in it
if a[i].Title <= b[j].Title
That <= means: on a tie, the LEFT half wins. The left half is the one that
came earlier in the original slice — so equal items keep their original order.
Write < instead and the sort still works. Tests that only check ordering will
pass. But stability is gone — and step 5 shows where that matters.
Quicksort
QuickSort(items):
if len(items) <= 1: return
p ← Partition(items, pivotIndex)
QuickSort(items[:p])
QuickSort(items[p+1:])
Partition(items, pivotIdx):
move items[pivotIdx] to the front (moves.Hit() if it moved)
pivot ← items[0].Title
i ← 1
for j from 1 to len(items)-1:
cmp.Hit()
if items[j].Title < pivot:
swap items[i] and items[j]; moves.Hit(); i ← i + 1
swap items[0] and items[i-1]; moves.Hit()
return i-1
Here it is the other way round: all the work is in the split, and there is nothing to put back together — once both halves are sorted, the slice is sorted.
And it works in place: no second array, unlike merge sort.
But the pivot is a guess
Partition divides the slice at the pivot. If the pivot is the median you get
two equal halves and a depth of log₂ n.
If the pivot is the smallest element, the left side is empty and the right side has n−1 items. And then the same thing again, every level down.
When is the pivot repeatedly the smallest? When you take the first element and the slice is already sorted.
Guess before you read on
In lesson 7, -order sorted was insertion sort's best case: 9,999
comparisons instead of 25 million.
What will the same flag do to a quicksort with a first-element pivot?
Write your guess down. Most people expect sorted input to be less work.