What is Selection Sort?
Selection sort builds the sorted array from the left: on each pass it scans the unsorted part for the smallest element and swaps it into the first unsorted position. It always makes n(n − 1)/2 comparisons, so it is O(n²) in every case, but it performs at most n − 1 swaps and needs only O(1) extra memory. It is not stable.
How it works
- Treat
A[0..i−1]as sorted (empty at first) andA[i..n−1]as unsorted. - Set
min = i, then scanjfromi + 1to the end; wheneverA[j] < A[min], setmin = j. - Swap
A[i]withA[min](skip it whenmin == i). The smallest unsorted value is now in its final place. - Increase
iand repeat until one element is left — it must be the largest.
Worked example: sorting [38, 27, 43, 3, 9, 82, 10]
The visualizer above opens on this array. Each pass scans the rest of the array and makes at most one swap:
- i = 0: the scan finds 3 → swap it with 38:
[3, 27, 43, 38, 9, 82, 10]. - i = 1: minimum 9 → swap with 27:
[3, 9, 43, 38, 27, 82, 10]. - i = 2: minimum 10 → swap with 43:
[3, 9, 10, 38, 27, 82, 43]. - i = 3: minimum 27 → swap with 38:
[3, 9, 10, 27, 38, 82, 43]. - i = 4: 38 is already the minimum — no swap.
- i = 5: minimum 43 → swap with 82:
[3, 9, 10, 27, 38, 43, 82].
That is 6 + 5 + 4 + 3 + 2 + 1 = 21 comparisons but only 5 swaps. Bubble sort needs 11 swaps on the same input.
Why it is always O(n²), even on sorted input
The inner loop can never stop early: to be sure A[min] is the smallest, it has to look at every remaining element. Pass i always makes n − 1 − i comparisons, for n(n − 1)/2 in total, whether the input is sorted, reversed or random.
That makes selection sort non-adaptive. An already sorted array of 1,000 elements still costs 499,500 comparisons (it just makes zero swaps), while insertion sort would finish it in 999. Load the Sorted preset above and watch the scans happen anyway.
Why selection sort is not stable
The long-distance swap is the culprit. Take [5a, 5b, 2]: the first pass swaps 5a with 2, giving [2, 5b, 5a], and the two 5s have changed order for good.
You can make selection sort stable by inserting the minimum and shifting the elements in between one place right instead of swapping, but that turns its O(n) writes into O(n²) — and the low write count was its main advantage. The Dupes preset tags repeated values *a*, *b*, … so you can watch them get reordered.
When selection sort makes sense
Its one real strength is the write count: at most n − 1 swaps, whatever the input. That matters when writing is much more expensive than reading — flash memory with limited write cycles, or records that are expensive to move. (Cycle sort takes the idea further and writes each element at most once.) For anything else, insertion sort is the better simple sort.
Selection sort is also the idea behind heap sort. Heap sort repeatedly selects the maximum too, but a binary heap finds it in O(log n) instead of an O(n) scan, which brings the total down to O(n log n).
Common mistakes and interview tips
- Swapping inside the inner loop every time a smaller value turns up. That is a different, slower algorithm; selection sort swaps once per pass.
- Running the outer loop to
ninstead ofn − 1: the last element is already in place. - Claiming an O(n) best case. The comparisons don't depend on the input order at all.
- Follow-up: “find the k smallest elements”. Stopping selection sort after k passes costs O(nk); a heap does it in O(n log k).
Time and space complexity
| Case | Time | Space | Why |
|---|---|---|---|
| Best | O(n²) | O(1) | Sorted input still needs n(n − 1)/2 comparisons; it makes 0 swaps. |
| Average | O(n²) | O(1) | Comparisons never change; swaps stay at most n − 1. |
| Worst | O(n²) | O(1) | n(n − 1)/2 comparisons and n − 1 swaps. |
Selection Sort in Python
def selection_sort(A):
# Sorts list A in place, ascending. NOT stable, O(1) extra space.
n = len(A)
for i in range(n - 1): # i = 0 .. n-2
min_idx = i # "min" in the pseudocode
for j in range(i + 1, n): # scan the unsorted part
if A[j] < A[min_idx]:
min_idx = j
if min_idx != i: # at most one swap per pass
A[i], A[min_idx] = A[min_idx], A[i]
# A[0..i] is now finalThe visualizer above shows the same code in Python, C++, Java and JavaScript.
Frequently asked questions
Is selection sort stable?
No. Swapping the minimum into place can jump an element over an equal one: [5a, 5b, 2] becomes [2, 5b, 5a].
What is the time complexity of selection sort?
O(n²) in the best, average and worst case, because it always makes n(n − 1)/2 comparisons. Only the number of swaps (0 to n − 1) depends on the input.
How many swaps does selection sort make?
At most n − 1, one per pass, and fewer when an element is already in place. Bubble and insertion sort instead move elements once per inversion, up to n(n − 1)/2 times.
What is the difference between selection sort and bubble sort?
Both are O(n²), but selection sort makes one swap per pass while bubble sort swaps every out-of-order pair of neighbours. Bubble sort is stable and can stop early on sorted input; selection sort is neither.
Is selection sort in-place?
Yes. It only needs a few index variables, so its extra space is O(1).
Keep learning
- Insertion Sort VisualizerInsertion sort takes each element and slides it left into place in the sorted prefix. Watch every shift animated, with Python code and O(n²) complexity.
- Bubble Sort VisualizerBubble sort repeatedly swaps adjacent out-of-order elements until a pass makes no swaps. Watch it step by step, with Python code and O(n²) complexity explained.
- Heap Sort VisualizerHeap sort visualizer: build a max-heap, then swap the root to the end and sift down, step by step. O(n log n) worst case, in place but not stable, with code.
- Quick Sort VisualizerQuick sort picks a pivot, moves smaller values left and larger ones right, then recurses: O(n log n) on average. Watch Lomuto and Hoare partitioning animated.
- Sorting Algorithm VisualizerSorting algorithm visualizer: watch bubble, selection, insertion, shell, counting, radix, merge and quick sort step by step, then race them in Compare mode.
Last updated