Linear Structures
Binary search
Halving the haystack every step
Your first real algorithm - and the purest example of logarithmic thinking. Halve the problem every step, and a million items surrender in twenty questions.
You have played "guess my number between 1 and 100." You do not guess 1, 2, 3... you guess 50, then halve. That halving is binary search - and it is why you can find a name in a phone book of millions in a couple dozen glances. The catch: it only works on sorted data.
The idea in one line
Step through it yourself
Click any value in the sorted array to search for it, then use Prev/Next to walk through the algorithm one comparison at a time. Watch the grayed-out cells: every step, half the remaining range disappears. The counters compare binary search against a plain left-to-right linear scan.
Target is 42. It could be anywhere in the range lo...hi.
Why "looks" grow so slowly
Where the log comes from
After comparisons, the range has shrunk from to . The search ends when only one candidate is left:
So binary search runs in time - the number of steps is the number of times you can halve before hitting 1.
Writing it without bugs
Binary search is famous for being easy to get subtly wrong - the loop bounds and the calculation are where off-by-one bugs live. Here is the clean version:
def binary_search(arr, target):
lo, hi = 0, len(arr) - 1 # inclusive range [lo, hi]
while lo <= hi: # stop when the range is empty
mid = lo + (hi - lo) // 2 # avoids overflow; same as (lo+hi)//2
if arr[mid] == target: return mid
elif arr[mid] < target: lo = mid + 1 # target is to the right
else: hi = mid - 1 # target is to the left
return -1 # not foundTwo classic traps
Check yourself
What must be true of the array for binary search to be correct?
Roughly how many comparisons does binary search need for one million sorted items?
What does binary search throw away at each step, and what does that guarantee?
Recall the loop invariant. Try to state it, then check.
Lock it in
- Keep a range that must contain the target, check the middle, and throw away the half that cannot hold it - each step halves what is left.
- That halving runs in : the number of halvings from to 1 is , about 20 for a million items.
- It is only correct on sorted data; on unsorted input it is wrong, not merely slow.
- Compute to avoid integer overflow, never .
Primary source
Ask your teacher