Quickselect

Context: FIT2004_MOC · Quick Sort’s partition reused for a different problem — find the -th smallest without sorting · the canonical decrease-and-conquer win: recurse into one side, not both · worst case eliminated by Median of Medians

Quick Revision

  • 🎯 Objective: partition once, then discard the side that cannot contain rank expected, beating sort-then-index’s .
  • 📦 Core Components: partition (shared with Quick Sort) ➔ pivot lands final at index | compare to decision | one-sided recursion ➔ the entire difference from quicksort.
  • ⚡ Key Constraint: is expected, not guaranteed — bad pivots give ; only a Median of Medians pivot makes a worst-case bound.

📝 How It Works

1. The Selection Problem

  • Specification ➔ given unsorted orderable items and a rank , return the element that would sit at index if the list were sorted — without producing the sorted list.
  • Median is the special case; the median is what makes selection worth a dedicated algorithm, because it is the pivot Quick Sort wants.
  • Sorting is over-solving ➔ sort-then-index answers every rank at once for ; selection answers one rank for . Choosing sorting when one rank is asked is the LO3 error.

2. One-Sided Recursion — The Whole Idea

  • Partition tells you the pivot’s TRUE rank ➔ after partition(lo, hi) returns boundary , the pivot is at its final sorted index; everything left of is smaller, everything right is larger — with zero further work.
  • Three-way decisiondone, return it · ⟹ the answer is in [lo, j-1], throw the right side away · ⟹ recurse on [j+1, hi] with unchanged (absolute indices).
  • Why the cost collapsesQuick Sort recurses on both halves so every level still costs across levels; quickselect recurses on one, so the level costs halve — a geometric series with that sums to Geometric Series.

3. Cost Profile

  • Expected under balanced pivots ⟹ root-dominated regime () ⟹ Solving Recurrences (Telescoping).
  • Worst ➔ an extreme pivot every level peels one element ⟹ by the Arithmetic Series — the same failure mode as Quick Sort, reached by the same inputs.
  • Auxiliary space is when written iteratively ➔ the recursion is tail recursion (nothing happens after the recursive call), so it rewrites as a while loop over lo/hi ⟹ genuinely in-place, unlike Quick Sort, whose second call cannot be eliminated.
  • Destructive ➔ partitioning permutes the caller’s array; if the original order matters, copy first and pay space.

⚙️ Core Implementation

🔹 Iterative quickselect — auxiliary

⚖️ Core Decision Matrix

ApproachTimeAuxiliary spaceNeeds all upfront?Selection rule
Sort, then index merge · quickYesmany ranks queried, or the sorted list is wanted anyway
Quickselect (random pivot) expected, worst iterativeYesone rank, array in memory, mutation acceptable
Quickselect Median of Medians worstYesa guarantee is required (real-time, adversarial input)
Size- heap ➔ Online AlgorithmNo — streams unknown or unbounded, or all smallest wanted, not just the -th

When It Flips: quickselect wins while exactly one rank is needed from a resident array. Ask for different ranks and sorting once amortises better; drop the "resident array" assumption and quickselect is unusable at any cost, because it must partition the whole input — that regime belongs to the size- heap in Online Algorithm.

📊 Exam Execution Trace & Applied Exercises

Manual Execution Trace

quickselect([7, 2, 9, 1, 5, 8, 3], k=2) — the rd smallest. Pivot middle element of the live window (Lomuto, as in Quick Sort).

StepWindow [lo, hi]PivotArray after partitionBoundary Decision
0 (Init)[0, 6][7, 2, 9, 1, 5, 8, 3]
1[0, 6][1, 2, 9, 7, 5, 8, 3]lo = 1
2[1, 6][1, 3, 2, 5, 7, 8, 9]hi = 3
3[1, 3][1, 2, 3, 5, 7, 8, 9]lo = 2
4[2, 3][1, 2, 3, 5, 7, 8, 9]return

Window sizes — the discarded halves are never revisited, and the array is left partially sorted only: rank is correct, ranks and happen to be settled by luck, and nothing else is guaranteed.

Applied Exercise

Problem: Derive quickselect’s expected time from its recurrence, and contrast the level sum with Quick Sort’s.

Final Extracted Output: expected — the factor is bought by the second recursive call, so deleting it deletes the factor. Worst case is still via .

⚠️ Common Mistakes

  • 💡 Quoting with no case is the expected/average bound; the worst case is unless you name the pivot policy. “Quickselect is linear” is only true of the Median of Medians variant ➔ Big-O Notation.
  • 💡 Translating when recursing right ➔ with absolute indices lo/hi, never changes; subtracting is only correct if the recursive call re-indexes the sub-array from . Pick one convention and state it.
  • 💡 Assuming the array is sorted afterwards ➔ only rank is final; the two sides are partitioned, not ordered — an exam answer that then indexes rank for free is wrong.

🧠 Active Recall