Cheatsheet
Algorithms: Searching and Simple Sorting
Binary search and the three simple sorts on one page: when each fits, what it costs, and the Python to write it.
ravnary.com/cheatsheets/algorithms-searching-and-simple-sorting · Checked against Python 3.14.
Scope
Binary search, its lower and upper bounds, and bubble, selection and insertion sort; faster sorts are on the Efficient Sorting sheet.The rule
Binary search needs sorted items and halves the range at each step; each simple sort grows a sorted part one item at a time, in O(n²) at worst.
Choosing
5 choicesWhen The items are sorted, and you need where a value belongs or how many items equal it
, chooseWhen The items are sorted, and you look one value up, perhaps many times
, chooseWhen There are only a few items, or the input is already nearly sorted
, chooseWhen Writing an item costs far more than comparing two
, chooseWhen You need one pass that also confirms the input is already sorted
, choose
Searching a sorted array
2 entriesBoth halve a sorted range: one finds a value, and the other finds where a value belongs.
Compare with the middle of a sorted range, then discard the half that cannot hold the target.
Use when
The items are sorted, and you look one value up, perhaps many times.
Facts
- Find
- O(log n)
- worst case, the range halves at each step
- Find
- O(1)
- best case, the target is the first midpoint
- Extra space
- O(1)
- every case, two indices and a midpoint
Snippet
py def binary_search(items, target): low, high = 0, len(items) - 1 while low <= high: mid = low + (high - low) // 2 if items[mid] == target: return mid if items[mid] < target: low = mid + 1 else: high = mid - 1 return -1Binary search over [low, high) that returns where a value belongs, not only whether it is there.
Use when
The items are sorted, and you need where a value belongs or how many items equal it.
Facts
- Lower bound
- O(log n)
- worst case, the first index whose item is at least the target
- Upper bound
- O(log n)
- worst case, the first index whose item is greater than the target
- Count of the target
- O(log n)
- worst case, upper bound minus lower bound
Snippet
py def lower_bound(items, target): low, high = 0, len(items) while low < high: mid = low + (high - low) // 2 if items[mid] < target: low = mid + 1 else: high = mid return low
Simple sorts
3 entriesEach grows a sorted part one item at a time, and they differ in where the next item comes from.
Take the next item and shift larger sorted items right until its place opens.
Use when
Few items, or input that is already nearly sorted, or items arriving one at a time.
Facts
- Time
- O(n)
- best case, the input already sorted
- Time
- O(n²)
- average and worst case, reversed input is the worst
- Stable
- yes
- in every case, equal items never pass each other
Snippet
py def insertion_sort(items): for i in range(1, len(items)): current = items[i] j = i - 1 while j >= 0 and items[j] > current: items[j + 1] = items[j] j -= 1 items[j + 1] = currentFind the smallest of what remains, then swap it to the front of the unsorted part.
Use when
Writing an item costs far more than comparing two, so the fewest swaps wins.
Facts
- Comparisons
- n(n − 1)/2
- every case, so O(n²) even on sorted input
- Swaps
- n − 1
- worst case, at most one per position
- Stable
- no
- in general, a long swap can carry an item past its equal
Snippet
py def selection_sort(items): for i in range(len(items) - 1): least = i for j in range(i + 1, len(items)): if items[j] < items[least]: least = j items[i], items[least] = items[least], items[i]Swap neighbours that are out of order; each pass carries the largest remaining item to the end.
Use when
Teaching, or one pass that also confirms the input is already sorted.
Facts
- Time
- O(n)
- best case, sorted input with the early exit
- Time
- O(n²)
- average and worst case, reversed input is the worst
- Stable
- yes
- in every case, only unequal neighbours swap
Snippet
py for end in range(len(items) - 1, 0, -1): swapped = False for j in range(end): if items[j] > items[j + 1]: items[j], items[j + 1] = items[j + 1], items[j] swapped = True if not swapped: break
Side by side
2 tables| Algorithm | Sorted part grows at | Next item comes from | Reach for it when |
|---|---|---|---|
| Bubble sort | The right end | The largest unsorted item, carried right by swapping neighbours | Teaching, or checking in one pass that data is already sorted |
| Selection sort | The left end | The smallest unsorted item, found by scanning all of them | Moving an item costs far more than comparing two, since it makes at most n − 1 swaps |
| Insertion sort | The left end | The next item in the array, slid left into its place | The input is small, nearly sorted, or arrives one item at a time |
| Target | Lower bound | Upper bound | Count, upper minus lower |
|---|---|---|---|
| 1 | 0 | 1 | 1 |
| 3 | 1 | 4 | 3 |
| 4 | 4 | 4 | 0 |
| 7 | 5 | 6 | 1 |
| 8 | 6 | 6 | 0 |
Common mistakes
3 mistakesComputing the midpoint as (low + high) / 2 in Java, which overflows past about a billion.
Reading a negative result from Java's binarySearch as only not found, when it encodes the insertion point.
Reading a Negative Result From Java's binarySearch as Only Not Found
Expecting an O(n) best case from a bubble sort that never checks for a pass without swaps.
Expecting an O(n) Best Case From a Bubble Sort Without the Early Exit
Learn it
2 topicsBinary Search5 questions
PractiseElementary Sorting5 questions
Practise