Skip to content

Selection Sort Visualizer

O(n²) avgunstablein-place
1/41

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

  1. Treat A[0..i−1] as sorted (empty at first) and A[i..n−1] as unsorted.
  2. Set min = i, then scan j from i + 1 to the end; whenever A[j] < A[min], set min = j.
  3. Swap A[i] with A[min] (skip it when min == i). The smallest unsorted value is now in its final place.
  4. Increase i and 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 n instead of n − 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

CaseTimeSpaceWhy
BestO(n²)O(1)Sorted input still needs n(n − 1)/2 comparisons; it makes 0 swaps.
AverageO(n²)O(1)Comparisons never change; swaps stay at most n − 1.
WorstO(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 final

The 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

Last updated