Quicksort: partition around a pivot
Picture
For [4,1,3,2], choose 3. We want smaller values before it and larger values after it.
Predict
Does a fixed bad pivot keep O(n log n) time?
Walk through the small example
No. A partition invariant can put one pivot in its final rank without sorting the entire range.
Mental model and complete Python solution
During partition, everything before the boundary is at most the pivot; everything between boundary and scan is known to be greater. Each inspected value extends one region.
What the function promises: Mutate a list of comparable values into nondecreasing order. This teaching version uses the final item as pivot and can degrade on ordered input.
def quicksort(values):
def sort(left, right):
if left >= right:
return
pivot = values[right]
boundary = left
for scan in range(left, right):
if values[scan] <= pivot:
values[boundary], values[scan] = values[scan], values[boundary]
boundary += 1
values[boundary], values[right] = values[right], values[boundary]
sort(left, boundary - 1)
sort(boundary + 1, right)
sort(0, len(values) - 1)
return values
assert quicksort([4,1,3,2,1]) == [1,1,2,3,4]
Work and storage: Average O(n log n), worst-case O(n²); recursion can reach O(n).
When to recognize it: A partition invariant can put one pivot in its final rank without sorting the entire range.
Check before applying it: Repeatedly choosing an extreme pivot creates quadratic work and deep recursion.
Change one rule
Adversarial input can choose the order.
See what changes
Randomize the pivot or use an introspective production sort with a worst-case fallback.
Connect
invariants: Partitioning grows regions with precise meanings.
Kth Largest Element: Partition only the side containing one requested rank.