Quicksort

Partition, recurse. Average n log n, worst n².

Quicksort picks a pivot, partitions (smaller left, larger right), then recurses. Average Θ(n log n). Worst Θ(n²) if every pivot is the extreme.

Goal

Partition a price list, then quicksort it. Count comparisons.

Partition

def partition(xs, lo, hi):
    pivot = xs[hi]
    i = lo
    steps = 0
    for j in range(lo, hi):
        steps += 1
        if xs[j] <= pivot:
            xs[i], xs[j] = xs[j], xs[i]
            i += 1
    xs[i], xs[hi] = xs[hi], xs[i]
    return i, steps

xs = [31, 10.5, 22.0, 10.5, 7]
idx, steps = partition(xs, 0, len(xs) - 1)
print("pivot index", idx, "steps", steps, "xs", xs)

Recurse

def quicksort(xs, lo=0, hi=None, steps=0):
    if hi is None:
        hi = len(xs) - 1
        xs = list(xs)
    if lo >= hi:
        return xs, steps
    pivot = xs[hi]
    i = lo
    for j in range(lo, hi):
        steps += 1
        if xs[j] <= pivot:
            xs[i], xs[j] = xs[j], xs[i]
            i += 1
    xs[i], xs[hi] = xs[hi], xs[i]
    xs, steps = quicksort(xs, lo, i - 1, steps)
    xs, steps = quicksort(xs, i + 1, hi, steps)
    return xs, steps

print(quicksort([31, 10.5, 22.0, 10.5, 7]))
print(quicksort([1, 2, 3, 4, 5]))

Already-sorted input with last-element pivot is the ugly case: one side empty each time.

Pitfall

This is not list.sort (Timsort). Production: sorted(xs). This chapter exists so average vs worst is a table you can print, not a slogan.