awesome-everything RU
↑ Back to the climb

Algorithms from zero

Sorting and search: code reading

Crux Read real sorting and search snippets — binary-search off-by-ones, the Lomuto partition, merge stability, and quickselect — predict the bug or behaviour, and pick the fix.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at middle altitude — in the sky
◷ 14 min

Sorting and search bugs hide in the boundaries: a wrong comparison, a half discarded one index too far, a swap that loses stability. Read each snippet the way you would in review and name the defect — or the exact behaviour — before you pick.

Goal

Practise the reviewer’s loop for this unit: trace the invariant in your head, find the off-by-one or the lost guarantee, and choose the minimal correct fix.

Snippet 1 — the infinite loop

function bsearch(arr, target) {
  let lo = 0, hi = arr.length - 1;
  while (lo <= hi) {
    const mid = Math.floor((lo + hi) / 2);
    if (arr[mid] === target) return mid;
    if (arr[mid] < target) lo = mid;   // discard left
    else hi = mid - 1;                 // discard right
  }
  return -1;
}
Quiz

On many inputs this hangs forever. What is the bug and the fix?

Snippet 2 — the integer-overflow midpoint

int bsearch(int arr[], int n, int target) {
    int lo = 0, hi = n - 1;
    while (lo <= hi) {
        int mid = (lo + hi) / 2;        // <-- here
        if (arr[mid] == target) return mid;
        if (arr[mid] < target) lo = mid + 1;
        else hi = mid - 1;
    }
    return -1;
}
Quiz

This passed every small test but corrupted results on a multi-gigabyte sorted array of 32-bit ints. Why, and what is the canonical fix?

Snippet 3 — the Lomuto partition

function partition(arr, low, high) {
  const pivot = arr[high];
  let i = low - 1;
  for (let j = low; j < high; j++) {
    if (arr[j] < pivot) {
      i++;
      [arr[i], arr[j]] = [arr[j], arr[i]];
    }
  }
  [arr[i + 1], arr[high]] = [arr[high], arr[i + 1]];
  return i + 1;
}
Quiz

What does the returned index guarantee, and why does this scheme make quicksort unstable?

Snippet 4 — quickselect for the k-th smallest

function quickselect(arr, k, lo = 0, hi = arr.length - 1) {
  const p = partition(arr, lo, hi);    // pivot's final index
  if (p === k) return arr[p];
  if (p < k) return quickselect(arr, k, p + 1, hi);
  return quickselect(arr, k, lo, p - 1);
}
Quiz

Quickselect finds the k-th smallest element by reusing partition. What is its complexity, and why is it better than sorting for this task?

Recap

Every defect here lives at a boundary: binary search must shrink the range (lo = mid + 1, never lo = mid) and compute mid = lo + (hi - lo) / 2 to dodge overflow; Lomuto partition returns the pivot’s final sorted position and is unstable because swaps cross equal keys; and quickselect reuses that partition to find the k-th element in O(n) average by recursing into only one side. Read the invariant first, then the fix is usually one token.

Continue the climb ↑Sorting and search: build a query engine
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.