Chapter 12: Sorting and Searching Algorithms
1. Why do we sort and search?
- Computers spend a lot of time putting data in order (sorting) or finding something inside ordered data (searching).
- Good algorithms make these jobs much faster, especially as the list grows.
2. Selection Sort - "Pick the smallest each time"
| What happens | Picture it |
|---|---|
| Look through the whole list, find the smallest item, put it in front. Then repeat with the rest of the list. | Like choosing the shortest player to stand first in a line, then the next shortest, and so on. |
-
Steps
- Start at position 0.
- Scan the rest of the list to find the minimum.
- Swap it into position 0.
- Move to position 1 and repeat until the end.
-
Cost: always comparisons (slow for big lists).
-
When it's fine: tiny lists, or when swapping is expensive but comparisons are cheap.
3. Insertion Sort - "Build the list like arranging playing cards"
- You keep a sorted left side and insert the next item into its proper spot.
[sorted part] | key | [unsorted part]-
In the worst case (list is backwards) it still does about
n(n-1)/2moves → . -
Best case (nearly sorted): almost no moves → close to !
-
Stable (equal items keep their original order).
-
Great for:
- Very small lists (it's what Python's built-in
sortuses for tiny chunks). - Touch-ups on nearly-sorted data.
- Very small lists (it's what Python's built-in
4. Merge Sort - "Divide, sort, and stitch together"
- Divide the list in half until you have single-element lists.
- Merge pairs of lists back together, always pulling out the smaller front item.
- Time: Every level of the "split/merge" tree touches all
nitems, and the tree height islogz n→ guaranteed. - Space: Needs extra arrays during merging (not in-place).
- Stable and predictable, good for huge datasets where worst-case time must be bounded.
5. Quick Sort - "Partition around a pivot"
- Pick a pivot value.
- Put smaller items on the left, larger on the right.
- Recursively sort the two halves.
- Average/Best: - often faster than merge sort in practice because of cache friendliness and no extra arrays.
- Worst: if pivots are terrible (e.g., always choose the first element and the list is already sorted).
- Tips to avoid worst-case: choose a random pivot or the median of three elements.
- Not stable, but in-place (uses little extra memory).
6. Binary Search - "Halve the search space"
-
Works only on a sorted list.
-
Compare target with the middle item:
- If equal → found.
- If smaller → search left half.
- If larger → search right half.
-
Repeats until the range is empty.
-
Time: each step halves the range → .
-
Return: often the index, or
-1if not present.
7. bisect Module - "Binary search built-in"
Python's bisect gives you the same power without writing the loop:
| Function | What it does |
|---|---|
bisect_left(a, x) | Index to insert x before equal items. |
bisect_right(a, x) | Index to insert x after equal items. |
insort_left(a, x) | Insert x in place, keeping the list sorted (shifts items). |
insort_right(a, x) | Same but after equal items. |
- Lookup is , insertion is because items move to make room.
8. Cheat-Sheet Comparison
| Algorithm | Typical Time | Worst-Case | Extra Space | Stable? | Good For |
|---|---|---|---|---|---|
| Selection Sort | ❌ | Tiny lists, minimal swaps | |||
| Insertion Sort | (see note 1) | ✅ | Small or nearly-sorted data | ||
| Merge Sort | ✅ | Large datasets, need stability | |||
| Quick Sort | (see note 2) | ❌ | General-purpose fastest | ||
| Binary Search | - | - | Finding items in sorted lists |
Notes
- Best case is close to
- Average extra space (call stack)
9. Key Take-Aways
- Know your data size & ordering - simple sorts are fine for tiny inputs.
- Merge vs. Quick - merge is safer; quick is usually quicker.
- Binary search is a huge speed-up once the data is already sorted.
- Python tip: prefer the built-in
sorted()orlist.sort()(Timsort). They pick the best strategy automatically.