Selection sort in 3 minutes
Channel: Michael Sambol
Watch on YouTube →Algorithm • easy
Selection sort scans the unsorted portion of the array, finds the smallest value, and swaps it into position. Then it repeats on the rest.
It performs the **minimum** number of swaps of any comparison sort: at most n−1, regardless of input order. That's its one real advantage.
Comparisons stay at O(n²) even when the input is already sorted, so it's almost always slower than insertion sort in practice.
Typical Complexity Baseline
| Metric | Value |
|---|---|
| Time | O(n^2) |
| Space | O(1) |
| Complexity Note 3 | Swaps O(n) |
See It
A small animated SVG that illustrates the core idea the moving parts you need to keep in your head when you read the rest of the guide.
Each pass scans the unsorted region to find the minimum and swaps it to the front.
Watch First
A quick visual walkthrough before the detailed sections pick the format that helps you learn fastest.
Channel: Michael Sambol
Watch on YouTube →Mechanics
The building blocks and terminology you need before everything else clicks. Skim or deep-read.
What it is Index marking where the sorted prefix ends and the unsorted suffix begins.
Why it matters Sorted boundary is a required building block for understanding how Selection Sort stays correct and performant on large inputs.
What it is Inner loop that finds the index of the smallest value in the unsorted suffix.
Why it matters Minimum scan is a required building block for understanding how Selection Sort stays correct and performant on large inputs.
What it is Single swap that moves the minimum to the sorted boundary.
Why it matters Swap into place is a required building block for understanding how Selection Sort stays correct and performant on large inputs.
What it is Increment the boundary so the just-placed value is now part of the sorted prefix.
Why it matters Boundary advance is a required building block for understanding how Selection Sort stays correct and performant on large inputs.
What it is Sorts the input array directly using O(1) extra memory.
Why it matters Sorts the input array directly using O(1) extra memory. In Selection Sort, this definition helps you reason about correctness and complexity when inputs scale.
What it is Equal values may end up in a different relative order than the input. Selection sort is unstable by default.
Why it matters Equal values may end up in a different relative order than the input. Selection sort is unstable by default. In Selection Sort, this definition helps you reason about correctness and complexity when inputs scale.
What it is At most n−1 swaps total, the lowest of any comparison sort.
Why it matters At most n−1 swaps total, the lowest of any comparison sort. In Selection Sort, this definition helps you reason about correctness and complexity when inputs scale.
What it is Cannot start sorting until all input is available, unlike insertion sort.
Why it matters Cannot start sorting until all input is available, unlike insertion sort. In Selection Sort, this definition helps you reason about correctness and complexity when inputs scale.
Walkthrough
Every frame of the concept diagram, laid out top-to-bottom so you can scroll through the algorithm at your own pace.
Pass 1: start scanning from index 0. min so far = arr[0]=6.
arr[1]=3 < current min → new min = 3 (index 1).
arr[2]=8 ≥ 3 → min stays at index 1.
arr[3]=1 < current min → new min = 1 (index 3).
arr[4]=5 ≥ 1 → min stays at index 3.
arr[5]=2 ≥ 1 → min stays at index 3.
arr[6]=7 ≥ 1 → min stays at index 3.
Swap arr[0] ↔ arr[3]. arr[0]=1 is locked.
Pass 2: start scanning from index 1. min so far = arr[1]=3.
arr[2]=8 ≥ 3 → min stays at index 1.
arr[3]=6 ≥ 3 → min stays at index 1.
arr[4]=5 ≥ 3 → min stays at index 1.
arr[5]=2 < current min → new min = 2 (index 5).
arr[6]=7 ≥ 2 → min stays at index 5.
Swap arr[1] ↔ arr[5]. arr[1]=2 is locked.
Pass 3: start scanning from index 2. min so far = arr[2]=8.
arr[3]=6 < current min → new min = 6 (index 3).
arr[4]=5 < current min → new min = 5 (index 4).
arr[5]=3 < current min → new min = 3 (index 5).
arr[6]=7 ≥ 3 → min stays at index 5.
Swap arr[2] ↔ arr[5]. arr[2]=3 is locked.
Pass 4: start scanning from index 3. min so far = arr[3]=6.
arr[4]=5 < current min → new min = 5 (index 4).
arr[5]=8 ≥ 5 → min stays at index 4.
arr[6]=7 ≥ 5 → min stays at index 4.
Swap arr[3] ↔ arr[4]. arr[3]=5 is locked.
Pass 5: start scanning from index 4. min so far = arr[4]=6.
arr[5]=8 ≥ 6 → min stays at index 4.
arr[6]=7 ≥ 6 → min stays at index 4.
min was already at index 4 → no swap. arr[4]=6 locked.
Pass 6: start scanning from index 5. min so far = arr[5]=8.
arr[6]=7 < current min → new min = 7 (index 6).
Swap arr[5] ↔ arr[6]. arr[5]=7 is locked.
Sorted! Always n²/2 comparisons but only n-1 swaps.
Tradeoffs
When this technique wins, when it loses, and what to reach for instead.
Choose this when Choose selection sort when swap cost dominates comparison cost (e.g. moving large objects).
Tradeoff Insertion sort runs O(n) on nearly-sorted input; selection always runs O(n²).
Choose this when Selection sort does n−1 swaps total versus bubble's O(n²) swaps. Pick it when swaps are costly.
Tradeoff Both are O(n²) comparisons; bubble sort gets early-exit on sorted input, selection does not.
Choose this when Selection is simpler and clearer for tiny n.
Tradeoff Heap sort is O(n log n), practically always faster for n > ~50.
In Production
Where this shows up at real companies and what the on-call engineer learned the hard way.
Firmware for low-RAM devices sometimes selects sort small fixed-size buffers because it needs zero extra memory and fewer writes than bubble.
Takeaway Constant memory and minimal writes can matter more than asymptotic time for tiny n.
QuickSelect is a randomized cousin of selection sort, used to find the kth smallest in O(n). Production code (e.g. NumPy's partition) builds on this idea.
Takeaway Selection-style scans are the foundation for partial-sort and order-statistic algorithms.
Selection sort is often taught right after bubble sort because it isolates the 'find min' subroutine, a building block reused everywhere.
Takeaway Decomposing 'find then place' makes more advanced algorithms easier to understand.
Code
A clean reference implementation in TypeScript, Python, and Go. Switch languages with the toggle.
The outer loop tracks the sorted boundary. The inner loop finds the minimum index in the unsorted suffix. Exactly one swap per outer iteration.
Complexity: Time O(n²), Space O(1), Swaps ≤ n−1
Selection sort with swap-minimal property
function selectionSort(values: number[]): number[] {
const sortedValues = [...values]
for (let sortedBoundary = 0; sortedBoundary < sortedValues.length - 1; sortedBoundary += 1) {
let minimumIndex = sortedBoundary
for (let scanIndex = sortedBoundary + 1; scanIndex < sortedValues.length; scanIndex += 1) {
if (sortedValues[scanIndex] < sortedValues[minimumIndex]) {
minimumIndex = scanIndex
}
}
if (minimumIndex !== sortedBoundary) {
;[sortedValues[sortedBoundary], sortedValues[minimumIndex]] = [sortedValues[minimumIndex], sortedValues[sortedBoundary]]
}
}
return sortedValues
}
Watch Out
The bugs and edge cases that bite engineers most often. Skim before you ship.
Pro Tips
Small habits that pay off every time you reach for this pattern.
Pattern Recognition
Concrete signals that tell you this is the right pattern both at work and on LeetCode.
Practice
A curated easy-to-hard problem ladder. Each one reinforces a specific aspect of the pattern.
| # | Problem | Difficulty | Typical Complexity |
|---|---|---|---|
| 1 | Sort an Array | Medium | O(n²) for selection approach |
| 2 | Sort Colors | Medium | O(n) Dutch flag, O(n²) selection |
| 3 | Kth Largest Element in an Array | Medium | O(n) average with QuickSelect |
| 4 | Find K Closest Elements | Medium | O(log n + k) |
| 5 | Top K Frequent Elements | Medium | O(n log k) |
| 6 | K Closest Points to Origin | Medium | O(n log k) |
| 7 | Wiggle Sort | Medium | O(n) |