Skip to content
dsa/roadmap
← All cheat sheets
03

Simple Sorting & Searching

dsa.fetehadin.com
3.1 Selection Sort

Find the smallest remaining item and swap it to the front. Repeat. Simple, at most n − 1 swaps, but always O(n²) comparisons.

Best caseO(n²): it still scans for the minimum every pass
Average caseO(n²)
Worst caseO(n²): n(n−1)/2 comparisons
Swapsat most n − 1 (the fewest of the simple sorts)
SpaceO(1)
Stable · in-placeno · yes
  • ✗Swapping inside the inner loop every time a smaller item is found. Swap once, after the inner loop.
  • ✗Starting the inner loop at j = i instead of j = i + 1 (compares an item with itself).
  • ✗Claiming selection sort has an O(n) best case. It has none; it always scans.
3.2 Bubble Sort

Compare neighbours and swap them if they are out of order. After each pass the biggest remaining item has "bubbled" to the end.

Best case (already sorted)O(n): one pass, no swaps, stop
Average caseO(n²)
Worst case (reversed)O(n²): n(n−1)/2 comparisons and swaps
SpaceO(1)
Stable · in-placeyes · yes
  • ✗Looping j up to n - 1 in every pass instead of n - 1 - i. It still works, but does useless comparisons.
  • ✗Writing a[j] >= a[j+1]. Swapping equal items breaks stability.
  • ✗Reading past the array with j < n and then accessing a[j + 1].
3.3 Insertion Sort

Grow a sorted part on the left by inserting each new item into its correct place, like sorting cards in your hand. Fast on nearly sorted data.

Best case (already sorted)O(n): n − 1 comparisons, 0 shifts
Average caseO(n²)
Worst case (reversed)O(n²): n(n−1)/2 comparisons and shifts
SpaceO(1)
Stable · in-placeyes · yes
  • ✗Writing a[j] >= key in the while loop. That breaks stability.
  • ✗Forgetting j >= 0 in the loop condition, which reads a[-1].
  • ✗Putting a[j + 1] = key inside the while loop. It goes after the loop.
3.4 Pointer Sort

When records are big, don't move them. Sort an array of pointers (or indices) to the records instead, and only small addresses get swapped.

Comparisonssame as the underlying sort (here selection: n(n−1)/2)
Data moved per swapone pointer (8 bytes) instead of one whole record
TimeO(n²) with selection sort; O(n log n) with a fast sort
SpaceO(n) for the pointer array
Stable · in-placeno · no
  • ✗Swapping the records (swap(*p[i], *p[min])) instead of the pointers (swap(p[i], p[min])). That defeats the purpose.
  • ✗Comparing the pointers themselves (p[j] < p[min]) instead of what they point to (p[j]->score).
  • ✗Forgetting to initialise p[i] = &s[i] before sorting.
3.5 Linear Search

Check every item from left to right until you find the key or run out. Works on any array, sorted or not, but costs O(n).

Best caseO(1): key at index 0
Average case (found)(n + 1)/2 comparisons → O(n)
Worst caseO(n): last item or not present
Needs sorted data?No
SpaceO(1)
  • ✗Returning -1 inside the loop (in an else), which stops after checking only the first item.
  • ✗Looping with i <= n, one past the end.
  • ✗Forgetting that an unsorted array cannot use binary search.
3.6 Binary Search

On a sorted array, check the middle, then throw away the half that cannot contain the key. Each step halves the problem, so it takes O(log n).

Best caseO(1): key is at the first mid
Average / worst caseO(log n): about ⌊log₂ n⌋ + 1 comparisons
1,000,000 itemsat most 20 comparisons
Needs sorted data?Yes, and random access (an array, not a linked list)
SpaceO(1) iterative · O(log n) recursive (call stack)
  • ✗Using while (low < high) instead of low <= high. That misses a key when one item is left.
  • ✗Setting low = mid or high = mid instead of mid ± 1, which can loop forever.
  • ✗Running it on unsorted data. The result is meaningless.
3.7 Recursion Primer

A function that calls itself on a smaller problem until it reaches a base case. You need this for trees (Ch 6) and merge/quick sort (Ch 8).

factorial(n): timeO(n): n calls, O(1) work each
factorial(n): spaceO(n) stack frames
recursive binary search: timeO(log n)
recursive binary search: spaceO(log n) stack frames (iterative version: O(1))
  • ✗No base case, or a base case that is never reached (e.g. factorial(n + 1)).
  • ✗Forgetting to return the recursive call's result (bs(...) instead of return bs(...)).
  • ✗Thinking recursion is always slower or always better. It trades stack memory for simpler code.
Stable sort:
A sort that keeps equal keys in their original relative order.
In-place:
Uses only O(1) extra memory besides the input (recursion stack aside).
Pass:
One full sweep of the outer loop of a sort.
Pointer sort:
Sorting an array of pointers (or indices) to records instead of moving the records themselves.
Linear search:
Check each item in turn. O(n). Works on unsorted data.
Binary search:
Repeatedly halve a sorted range by comparing with the middle item. O(log n).
Recursion:
A function that calls itself on a smaller input, stopping at a base case.
Base case:
The input a recursive function answers directly, without recursing.
Call stack:
Memory where each active function call keeps its parameters and local variables.

Keyboard shortcuts

⌘K /
Search topics, glossary, cheat sheets
space
Play / pause the visualizer
← →
Step back / forward
r
Reset the visualizer
?
Show this help