How do simple comparison sorts work, and why are they quadratic?
Implement and trace bubble sort and insertion sort, analyse their complexity, and compare their behaviour on nearly sorted data
A focused answer to the H2 Computing outcome on elementary sorts. Bubble sort and insertion sort, tracing each on an example, their O(n squared) worst case, and why insertion sort excels on nearly sorted input.
Reviewed by: AI editorial process; not yet individually human-reviewed
Have a quick question? Jump to the Q&A page
Jump to a section
What this dot point is asking
SEAB wants you to implement and trace bubble sort and insertion sort, analyse their complexity, and compare how they behave - especially on nearly sorted data. The central idea is that both are simple comparison sorts, but insertion sort is adaptive: it does far less work when the input is already close to sorted.
The answer
Bubble sort
Bubble sort repeatedly walks the list comparing adjacent pairs and swapping any that are out of order. After each full pass the largest remaining element has "bubbled" to its correct place at the end:
def bubble_sort(data):
n = len(data)
for limit in range(n - 1, 0, -1):
swapped = False
for i in range(limit):
if data[i] > data[i + 1]:
data[i], data[i + 1] = data[i + 1], data[i]
swapped = True
if not swapped:
break # already sorted, stop early
return data
With elements it does about comparisons, so . The early-exit flag makes its best case on already-sorted data.
Insertion sort
Insertion sort builds a sorted region at the front, taking each new element and shifting it left into place:
def insertion_sort(data):
for i in range(1, len(data)):
key = data[i]
j = i - 1
while j >= 0 and data[j] > key:
data[j + 1] = data[j] # shift right
j = j - 1
data[j + 1] = key
return data
Worst case (reverse order) each element shifts past all before it: . Best case (already sorted) each element needs no shift: .
Behaviour on nearly sorted data
This is where they differ in practice. Insertion sort is adaptive: if most elements are already near their final places, each does only a few shifts, so the run is close to linear. Bubble sort with the early-exit flag also benefits, but typically performs more swaps. For small or nearly sorted lists, insertion sort is the usual choice and is used as the base case inside faster sorts.
Examples in context
Example 1. Sorting a hand of cards. Most people sort playing cards by insertion: pick up each card and slide it into the right spot among the cards already in order. The everyday method is exactly the insertion sort algorithm, and it feels fast because a hand is small and often nearly sorted.
Example 2. The base case of a fast sort. Production sorting libraries switch to insertion sort once a sublist is small (say under 16 elements), because its low overhead beats the recursion of merge sort or quicksort on tiny inputs. Its adaptive, low-constant behaviour makes it the ideal finisher.
Try this
Q1. After one full pass of bubble sort, what is guaranteed about the list? [1 mark]
- Cue. The largest unsorted element has moved to its correct final position at the end.
Q2. State the best-case complexity of insertion sort and the input that produces it. [2 marks]
- Cue. - on an already-sorted list, since each element needs no shifting.
Q3. Why is insertion sort preferred over bubble sort for nearly sorted data? [2 marks]
- Cue. It is adaptive: each element shifts only as far as needed, so few moves occur, approaching a single linear pass.
Exam-style practice questions
Practice questions written in the style of SEAB exam questions on this dot point, with worked answer explainers. The year tag is the paper they imitate, not the source.
Original6 marksTrace one full pass of bubble sort over the list , showing each comparison and any swap, and give the list after the pass. Explain what is guaranteed about the list after the first complete pass.Show worked answer →
Bubble sort compares adjacent pairs left to right, swapping when the left is larger.
| Compare | Pair | Swap? | List after |
|---|---|---|---|
| 5 vs 2 | (5,2) | yes | [2, 5, 9, 1, 6] |
| 5 vs 9 | (5,9) | no | [2, 5, 9, 1, 6] |
| 9 vs 1 | (9,1) | yes | [2, 5, 1, 9, 6] |
| 9 vs 6 | (9,6) | yes | [2, 5, 1, 6, 9] |
After the first pass the list is .
What is guaranteed: the largest value () has "bubbled" to its correct final position at the end of the list. Each subsequent pass fixes the next largest into place.
Markers reward the four adjacent comparisons with correct swaps, the resulting list, and the insight that the largest element is now in its final position.
Original5 marks(a) State the worst-case and best-case time complexity of insertion sort. (b) Explain why insertion sort performs very well on a list that is already nearly sorted. (c) Give one reason insertion sort is often preferred over bubble sort in practice.Show worked answer →
(a) Worst case (a reverse-sorted list, where each new element shifts past all the sorted ones); best case (an already-sorted list).
(b) Insertion sort takes each element and shifts it left only as far as needed to sit in order. On nearly sorted data, each element is already close to its place, so very few shifts occur per element - close to a single linear pass.
(c) Insertion sort generally does fewer data movements than bubble sort and is adaptive (fast on nearly sorted input), so it is faster in typical cases and is commonly used for small or almost-sorted lists, including as the base case inside faster sorts.
Markers reward the two complexities, the adaptive behaviour (few shifts when nearly sorted), and a valid practical advantage over bubble sort.
Related dot points
- Analyse the time and space complexity of an algorithm using Big-O notation, and compare common growth rates
A focused answer to the H2 Computing outcome on algorithmic complexity. Big-O notation, deriving the order of growth from loops and recursion, the common complexity classes, and the trade-off between time and space.
- Implement and trace linear search and binary search, state their complexities, and justify when each applies
A focused answer to the H2 Computing outcome on searching. Linear search and binary search, tracing each on an example, their O(n) and O(log n) complexities, and the precondition that binary search needs sorted data.
- Explain and trace merge sort and quicksort as divide-and-conquer algorithms, analyse their complexity, and compare their trade-offs
A focused answer to the H2 Computing outcome on efficient sorts. Merge sort and quicksort as divide-and-conquer, their O(n log n) behaviour, quicksort's worst case, and the trade-off between stability, memory and speed.
- Define recursion in terms of base and recursive cases, trace recursive calls, and compare recursion with iteration
A focused answer to the H2 Computing outcome on recursion. Base and recursive cases, tracing the call stack, the divide-and-conquer pattern, and the trade-offs between recursion and iteration.
- Describe arrays and records as data structures, explain constant-time array indexing and contrast static with dynamic arrays
A focused answer to the H2 Computing outcome on arrays and records. Contiguous storage and constant-time indexing, one and two dimensional arrays, records as fields of mixed type, and static versus dynamic arrays.