Skip to content

Intermediate: core algorithms · Sorting and searching · topic 26 of 61 · 35 min

Simple sorts: bubble, selection and insertion

Explanation

Bubble sort swaps neighbours that are out of order, selection sort picks the smallest remaining item each round, and insertion sort slides each new item back into its place like sorting playing cards. All three take O(n²) time and O(1) extra space. Insertion sort is fast on nearly sorted data, and bubble and insertion sort are stable: equal items keep their original order.

Why learn sorts you will not use?

In real code you call sorted() and move on. But interviewers ask about simple sorts because they teach the words used for every sort (pass, swap, in place, stable), they are easy to trace by hand, and insertion sort is genuinely used inside fast library sorts for small pieces. Sorting means putting items in order, here non-decreasing order: each item is less than or equal to the next.

Bubble sort

Walk through the list and compare each pair of neighbours; if the left one is bigger, swap them. After one pass the largest item has "bubbled" to the end, so the next pass can stop one place earlier. With an early exit, if a whole pass makes no swaps, the list is already sorted and you stop.

output
[5, 1, 4, 2]
pass 1: swap 5,1 → [1, 5, 4, 2]; swap 5,4 → [1, 4, 5, 2]; swap 5,2 → [1, 4, 2, 5]
pass 2: 1,4 fine; swap 4,2 → [1, 2, 4, 5]          (5 is already in place)
pass 3: 1,2 fine → no swaps, so stop early
Four swaps in total. Each swap fixes exactly one out-of-order pair.

Selection sort

Find the smallest item in the unsorted part and swap it to the front of that part; then the sorted part grows by one. It always does about n²/2 comparisons, even on sorted input, but at most n − 1 swaps, which matters only when writing to memory is very costly.

output
[29, 10, 14, 37, 13]
round 1: smallest is 10 → swap with 29 → [10, 29, 14, 37, 13]
round 2: smallest of the rest is 13 → swap with 29 → [10, 13, 14, 37, 29]
round 3: 14 is already in place
round 4: smallest of [37, 29] is 29 → swap → [10, 13, 14, 29, 37]

Insertion sort

This is how most people sort a hand of playing cards. The left part is always sorted. Take the next item (the key), shift every bigger item in the sorted part one place right, and drop the key into the gap.

python
def insertion_sort(nums):
    a = list(nums)                 # work on a copy
    for i in range(1, len(a)):
        key = a[i]
        j = i - 1
        while j >= 0 and a[j] > key:   # > (not >=) keeps equal items in order
            a[j + 1] = a[j]            # shift right
            j -= 1
        a[j + 1] = key
    return a

print(insertion_sort([5, 2, 4, 1]))   # Output: [1, 2, 4, 5]
For [5, 2, 4, 1]: 2 needs 1 shift, 4 needs 1, and 1 needs 3, so 5 shifts in all.

Insertion sort does one shift per inversion (a pair in the wrong order, as in Module 5). A nearly sorted list has few inversions, so insertion sort runs in about O(n + inversions), close to O(n). That is why library sorts use it for short or almost-sorted runs.

Costs at a glance

SortBestAverage and worstExtra spaceStable?
Bubble (early exit)O(n), already sortedO(n²)O(1)Yes
SelectionO(n²)O(n²)O(1)No
InsertionO(n), already sortedO(n²)O(1)Yes

In place means the sort rearranges the list itself, using only O(1) extra memory. All three are in place (the code above copies the input first only so the caller's list does not change).

Stability

A sort is stable if items with EQUAL keys keep their original relative order. Suppose a class list is in alphabetical order and you sort it by marks. With a stable sort, students who scored the same marks stay in alphabetical order, so you get "sorted by marks, then by name" for free.

python
students = [("Asha", 82), ("Kiran", 75), ("Meena", 82), ("Ravi", 75)]   # by name
print(sorted(students, key=lambda s: s[1], reverse=True))
# Output: [('Asha', 82), ('Meena', 82), ('Kiran', 75), ('Ravi', 75)]
Python's sort is stable, so Asha stays before Meena and Kiran before Ravi.

Selection sort is not stable because its long-distance swap can jump an item over an equal one. Sorting [(2, "a"), (2, "b"), (1, "c")] by the number, round 1 swaps (1, "c") with (2, "a"), giving [(1, "c"), (2, "b"), (2, "a")]: "b" is now before "a".

Common mistakes

  • Using >= instead of > when comparing in bubble or insertion sort. It still sorts, but equal items get swapped, so the sort is no longer stable. Fix: move an item only when it is strictly bigger.
  • Running bubble sort's inner loop to the end every pass. Fix: after pass k the last k items are final, so stop earlier.
  • Forgetting the early exit, so a sorted list still costs O(n²). Fix: track whether a pass swapped anything.
  • Off-by-one in insertion sort: losing the key by shifting before saving it. Fix: store key = a[i] first, and write it at a[j + 1] at the end.
  • Calling these sorts in production code. Fix: use the built-in sort; learn these for interviews and for small or nearly sorted data.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Simple sorts: bubble, selection and insertion · 1/8

Simple sorts

This lesson covers three simple sorts: bubble, selection and insertion. They are slow on big data, but they teach every word you need to talk about sorting.

Prefer a video by a teacher? Find free videos on “bubble sort selection sort insertion sort visualised stable sorting explained” on YouTube ↗

In real life: A leaderboard that is almost sorted

A quiz app for a coaching centre keeps its leaderboard sorted by score. When one student's score goes up, only that one entry is out of place. Re-sorting from scratch is wasteful; one step of insertion sort moves the entry left past the scores it now beats, which is O(n) at worst and often just a few moves. This is the "nearly sorted" case where insertion sort shines.

python
board = [("Neha", 95), ("Arjun", 90), ("Sara", 88), ("Vikram", 70)]
board[3] = ("Vikram", 92)          # Vikram's score improved
i = 3
while i > 0 and board[i - 1][1] < board[i][1]:
    board[i - 1], board[i] = board[i], board[i - 1]
    i -= 1
print(board)
Shows [('Neha', 95), ('Vikram', 92), ('Arjun', 90), ('Sara', 88)] after only two swaps.

Practice (0/3 done)

Task 1 · Code · Python

Write is_sorted(nums) that returns True if nums is in non-decreasing order (each item ≤ the next), else False. One pass, O(n) time, O(1) extra space; do not sort. Empty and one-item lists are sorted. Example: is_sorted([1, 2, 2, 5]) returns True.

Task 2 · Code · Python

Write insertion_sort(nums) that RETURNS A NEW sorted list (non-decreasing) and does not change nums. Write the algorithm yourself: do not call sorted() or .sort(). The tests can only check the results, so this is on your honour. Example: insertion_sort([5, 2, 4, 1]) returns [1, 2, 4, 5].

Task 3 · Code · Python

Write bubble_sort(nums) that sorts a COPY of nums with bubble sort and returns a tuple (sorted_list, swaps, passes). A pass walks the unsorted part from the left, swapping neighbours when the left one is STRICTLY bigger (equal items are never swapped). After each pass the unsorted part ends one place earlier. Stop as soon as a pass makes no swaps (that pass still counts), or when the unsorted part has fewer than 2 items. swaps is the total number of swaps; passes is the number of passes made. Do not call sorted() or .sort(). Example: bubble_sort([5, 1, 4, 2]) returns ([1, 2, 4, 5], 4, 3).

Quick quiz

Question 1

1.What does "stable sort" mean?

Question 2

2.Which simple sort is NOT stable?

Question 3

3.Insertion sort on a list that is already sorted takes…

Question 4

4.After the first pass of bubble sort on [4, 3, 1, 2], which item is guaranteed to be in its final place?

Question 5

5.How many swaps does bubble sort make on [3, 1, 2]?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

What does "stable sort" mean?

Answer: Items with equal keys keep their original relative order

Stability is about ties: equal items stay in the order they came in.

Which simple sort is NOT stable?

Answer: Selection sort

Selection sort's long-distance swap can jump an item over an equal one.

Insertion sort on a list that is already sorted takes…

Answer: O(n)

Each key is compared once with its left neighbour and nothing moves.

After the first pass of bubble sort on [4, 3, 1, 2], which item is guaranteed to be in its final place?

Answer: 4 at the end

Each pass carries the largest remaining item to the end of the unsorted part.

How many swaps does bubble sort make on [3, 1, 2]?

Answer: 2

Swaps equal inversions: (3, 1) and (3, 2), so 2.

What does it mean that Python's sort is stable?Related

Answer: Items that compare equal keep their original order

Stable sorting keeps equal items in the order they had before, which lets you sort by several keys in steps.

From Recursion and sorting algorithms

What is the time complexity of bubble sort in the worst case?Related

Answer: O(n²)

Nested loops over the array.

From 2D arrays and classic array algorithms

Quick sort always picks the last item as pivot. Which input is slowest?Related

Answer: A list that is already sorted

Each pivot is the largest item, so one side is empty every time: n levels, O(n²).

From Merge sort and quick sort

Which key sorts (name, marks) tuples by marks high to low, then name A to Z?Related

Answer: lambda s: (-s[1], s[0])

The tuple compares marks first (negated for high to low), then the name.

From Sorting in real code: keys, comparators, counting sort

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 4 more topics in “Sorting and searching” before its exam: Merge sort and quick sort, Sorting in real code: keys, comparators, counting sort, Binary search, Binary search on the answer.
  2. Module 6 exam: Sorting and searching · 14 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Trees and binary search trees. 61 topics left in the course before the final exam.

← Previous: Memoization: remembering answers