Selection Sort
BasisPrerequisites
Every swap in a sorting algorithm is a write to memory. Bubble sort can perform swaps in the worst case. Selection sort cuts that to at most swaps — one per pass — regardless of the input. When writes are expensive (flash storage, for instance), that matters.
The algorithm
Selection sort divides the array into a sorted prefix and an unsorted suffix. On each pass it scans the unsorted suffix for its minimum, then swaps that minimum into the first position of the unsorted suffix, growing the sorted prefix by one.
fn selectionSort(arr: []i64) void {
var i: usize = 0;
while (i < arr.len) : (i += 1) {
// Find the index of the minimum in arr[i..]
var min_idx = i;
var j = i + 1;
while (j < arr.len) : (j += 1) {
if (arr[j] < arr[min_idx]) min_idx = j;
}
// Swap minimum into position i
if (min_idx != i) {
const tmp = arr[i];
arr[i] = arr[min_idx];
arr[min_idx] = tmp;
}
}
}
The if (min_idx != i) guard avoids a no-op swap when the minimum is already at position i.
Correctness via loop invariant
Invariant: at the start of iteration , arr[0..i] contains the smallest elements of the original array in sorted order, and each is in its final position.
- Before iteration 0:
arr[0..0]is empty — vacuously true. - Maintenance: the inner loop finds
min_idx, the index of the minimum value inarr[i..]. After the swap,arr[i]holds that minimum. Sincearr[0..i]already contained the smallest elements,arr[i]is now the -th smallest. The prefixarr[0..i+1]is sorted and each element is in its final position. - Termination: increases by one each iteration. When , only one element remains in the suffix, which is already in its correct position by the invariant on the prefix.
When the loop exits, arr[0..arr.len] is the entire array in sorted order.
Why selection sort is not stable
Stability means that equal elements keep their original relative order. Selection sort is not stable: the minimum-finding swap can move an element past an equal neighbour.
Consider [5, 5*, 2] where 5* is a second copy of 5 (shown with a star to track its identity).
- Pass 0: minimum is
2at index 2. Swaparr[0]andarr[2]:[2, 5*, 5].
The original first 5 is now to the right of 5*, reversing their order. This violates stability.
Complexity
Comparisons
The inner loop runs times for , then times for , down to time for :
This count is the same for every input — sorted, reverse-sorted, or random — because the algorithm always scans the full unsorted suffix. Selection sort has no best case.
Swaps
At most swaps (one per pass, skipped when the minimum is already in place). This is , far fewer than bubble sort’s worst case.
Space
extra space — only index variables beyond the input array.
| Metric | Complexity |
|---|---|
| Comparisons | always |
| Swaps | |
| Extra space | |
| Stable | No |
When selection sort has an edge
- Write-heavy media: when each swap is expensive (SSD wear, remote write), swaps can beat algorithms with writes even if their comparison count is lower.
- Tiny arrays: at , the overhead of more sophisticated algorithms is not worth it.
For any larger input, insertion sort is a better in-place choice, and merge sort or quick sort give .
Summary
- Selection sort finds the minimum of the unsorted suffix and swaps it to the front of that suffix, growing a sorted prefix.
- The loop invariant guarantees correctness: after passes, the smallest elements are in their final positions.
- Comparisons are always — the input order makes no difference.
- Swaps are at most , which is the algorithm’s main practical advantage.
- Selection sort is not stable: swapping the minimum past equal elements can change their relative order.