Abstract
What if we designed an algorithm that takes as input a list of numbers of length and an integer , and outputs the smallest integer in the list?
- Category: Divide and Conquer / Selection (order statistics)
- Input: A list of numbers, and an integer with
- Output: The smallest element of the list
- Paradigm: Divide and Conquer (partition-based)
- Typical use cases: finding medians, general order statistics, percentile queries
Problem Specification
- Instance: A list of integers, and an integer with .
- Solution Format: A single integer — the smallest value in .
- Constraints: .
- Objective / Goal: Unlike the optimization problems elsewhere in this vault, Selection isn’t a “maximize/minimize over many valid solutions” problem — there’s exactly one correct answer per instance. The goal is instead to compute it correctly and quickly, ideally faster than the a full sort would cost.
Candidate Strategies / Approaches
Sort-then-Index
Sort the entire list, then return the element at index . Always correct, but costs — more work than necessary, since we only need to identify the rank of one element, not fully order all of them.
Divide and Conquer (Partition-Based) ✔
Applying the general Divide and Conquer recipe: break into similar subproblems (split the list), solve recursively (select from one sublist), combine (decide how to split again).
Just splitting down the middle doesn’t help — instead, pick a random pivot, and split the list into all elements smaller than the pivot and all elements larger. Then determine which side the smallest element must fall in (note that itself may need to change depending on which side we recurse into).
Key Idea
Unlike Merge Sort, Selection never needs to recurse on both halves — once we know which side of the pivot the answer lives on, the other side can be discarded entirely. That’s exactly what allows Selection to beat the sorting lower bound.
Partition with Pivot (Core Subroutine)
Given a list and a pivot , rearrange so that all elements smaller than are to the left of and all elements larger are to the right. This is the core operation both QuickSelect and Deterministic Selection are built on.
Design goals: linear time, and ideally in place (rearranging the list only by swapping elements, no auxiliary array).
Algorithm 12 Partition with Pivot
Input: List
Output: Rearranged list such that the elements smaller than pivot are to left and elements larger than pivot are to the right
procedure Partition()
while do
if then
if then
else
swap and
swap and
else
if then
else
swap and
swap and
Reading This Pseudocode
This partitions the list around the element that starts at index (i.e. acts as the pivot). Two pointers
iandhscan toward each other from opposite ends; whenever the scanning pointer finds an element on the wrong side of the current reference value, it’s swapped into place, and the roles ofiandhswap — which is why the pseudocode swaps the index variables themselves, not just the array values. This continues until the two pointers meet, at which point the list is fully partitioned. It answers both of the classic design questions: it’s linear time (each element is examined a bounded number of times asiandhconverge), and it’s in place (only swaps are used — no second array).
Worked Example
Selection([40, 31, 6, 51, 76, 58, 97, 37, 86, 31, 19, 30, 68], 7)Pick a pivot (). Divide the list into 3 groups:
- — all elements smaller than : , size
- — all elements equal to : , size
- — all elements greater than : , size
Since is bigger than , the smallest element can’t be in . Since is also bigger than , it can’t be in either — so it must be in .
Since elements () have already been accounted for as smaller than everything in , the smallest element overall is the smallest element within . Recurse on with the adjusted .
Chosen Approach
This note covers the shared problem framing and the Partition with Pivot subroutine both concrete algorithms rely on. The actual recursive selection algorithms — and their correctness proofs and complexity analyses — live in their own dedicated notes, since the choice of how to pick the pivot is what distinguishes them:
- QuickSelect — picks the pivot randomly; simple, expected time, but worst case.
- Deterministic Selection — picks the pivot via a guaranteed-good strategy (median-of-medians); worst-case time, at the cost of a larger constant factor.
Time & Space Complexity Analysis
Partition with Pivot (this note’s subroutine)
| Complexity | Notes | |
|---|---|---|
| Time | Single pass — the two pointers i, h converge, each element examined a bounded number of times | |
| Space | In place — only element swaps, no auxiliary array |
The complexity of the full selection algorithm depends entirely on how the pivot is chosen — see QuickSelect and Deterministic Selection for those analyses.
Deterministic vs. Randomized
| Deterministic | Randomized | |
|---|---|---|
| Selection | Deterministic Selection (Median of Medians) — | QuickSelect — Best: , Worst: , Average: |
See Deterministic vs. Randomized Approaches for the full table including Sorting.
Drawbacks / Constraints
- Sort-then-Index wastes work. Fully sorting costs when only one element’s rank is actually needed.
- Pivot choice matters enormously. A poor pivot (e.g. always the min or max) barely shrinks the problem each recursive call — see QuickSelect’s worst-case analysis for exactly how bad this gets.
- Not suitable for: repeated queries for many different values on the same list — if you need several order statistics from the same data, sorting once () and then indexing repeatedly ( each) can beat re-running Selection ( each) from scratch every time.