Searching & Sorting
Bubble, Selection & Insertion Sort
The three O(n²) sorts: how each one works, passes and swaps traced by hand, stability, best cases, and when a simple sort is the right choice.
Sorting puts elements in order. Sorted data makes searching (binary search), finding duplicates, merging and reporting much easier. We start with three simple sorts that are easy to trace by hand — exactly what exams ask.
Watch them run on the same data:
Bubble sort
Compare adjacent pairs and swap if they are in the wrong order. After pass 1 the largest element has "bubbled" to the end; after pass 2, the second largest; and so on. If a pass makes no swaps, the array is already sorted and we can stop early.
#include <stdio.h>
void show(const int a[], int n) { for (int i = 0; i < n; i++) printf("%d ", a[i]); printf("\n"); }
void bubbleSort(int a[], int n) {
for (int pass = 1; pass < n; pass++) {
int swapped = 0;
for (int j = 0; j < n - pass; j++)
if (a[j] > a[j + 1]) {
int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;
swapped = 1;
}
printf("after pass %d: ", pass); show(a, n);
if (!swapped) break; // no swaps: already sorted
}
}
int main(void) {
int a[] = {5, 1, 4, 2, 8};
bubbleSort(a, 5);
return 0;
}after pass 1: 1 4 2 5 8 after pass 2: 1 2 4 5 8 after pass 3: 1 2 4 5 8
Selection sort
Find the minimum of the unsorted part and swap it to the front of that part. Exactly n − 1 swaps — useful when writing to memory is expensive.
#include <stdio.h>
void show(const int a[], int n) { for (int i = 0; i < n; i++) printf("%d ", a[i]); printf("\n"); }
void selectionSort(int a[], int n) {
for (int i = 0; i < n - 1; i++) {
int min = i;
for (int j = i + 1; j < n; j++)
if (a[j] < a[min]) min = j;
int t = a[i]; a[i] = a[min]; a[min] = t;
printf("pass %d (placed %d): ", i + 1, a[i]); show(a, n);
}
}
int main(void) {
int a[] = {64, 25, 12, 22, 11};
selectionSort(a, 5);
return 0;
}pass 1 (placed 11): 11 25 12 22 64 pass 2 (placed 12): 11 12 25 22 64 pass 3 (placed 22): 11 12 22 25 64 pass 4 (placed 25): 11 12 22 25 64
Insertion sort
Build the sorted part one element at a time: take the next element (the key) and shift larger sorted elements right until the key's place is found — the way you sort playing cards in your hand.
#include <stdio.h>
void show(const int a[], int n) { for (int i = 0; i < n; i++) printf("%d ", a[i]); printf("\n"); }
void insertionSort(int a[], int n) {
for (int i = 1; i < n; i++) {
int key = a[i], j = i - 1;
while (j >= 0 && a[j] > key) {
a[j + 1] = a[j]; // shift right
j--;
}
a[j + 1] = key;
printf("insert %2d: ", key); show(a, n);
}
}
int main(void) {
int a[] = {12, 11, 13, 5, 6};
insertionSort(a, 5);
return 0;
}insert 11: 11 12 13 5 6 insert 13: 11 12 13 5 6 insert 5: 5 11 12 13 6 insert 6: 5 6 11 12 13
On nearly sorted data, insertion sort barely shifts anything and runs in close to O(n) — which is why fast library sorts switch to insertion sort for small pieces.
Comparison
| Bubble | Selection | Insertion | |
|---|---|---|---|
| Best case | O(n) (with early exit) | O(n²) | O(n) |
| Average / worst | O(n²) | O(n²) | O(n²) |
| Swaps / writes | many | n − 1 swaps | many shifts |
| Extra space | O(1) | O(1) | O(1) |
| Stable? | yes | no | yes |
| Adaptive (faster on sorted input)? | yes | no | yes |
Test yourself
4 questions · pick an answer to check it instantly
- 1
After the first pass of bubble sort on
[4, 3, 2, 1], what is the array?One pass moves the largest element (4) to the end: 4 swaps past 3, 2 and 1. - 2
Which simple sort makes at most n − 1 swaps?
Selection sort does one swap per pass. - 3
Which sort is fastest on an already sorted array?
Insertion sort does one comparison per element when nothing needs shifting: O(n). - 4
Which of these is not stable?
Selection sort's long-distance swap can jump an element past an equal one.