Algorithms
Binary Search
Find one item in a million in 20 lookups
Binary search is a divide-and-conquer search algorithm that finds a target value in a sorted array by repeatedly halving the search range. It runs in O(log n) time, meaning a one-million-element array takes at most 20 comparisons to search.
- Time (worst, average)O(log n)
- Time (best)O(1)
- Space (iterative)O(1)
- Requires sorted inputYes
- StableN/A (search, not sort)
Interactive visualization
Press play, or step through manually. The visualization is yours to drive — try it before reading on.
Watch the 60-second explainer
A condensed visual walkthrough — narrated, captioned, under a minute.
How binary search works
Imagine looking up a word in a printed dictionary. You don't start from page 1 — you flip to roughly the middle. If the word you want comes earlier alphabetically, you ignore the back half and repeat with the front half. Binary search does the same thing, on a sorted array, in code.
The algorithm tracks two indices, low and high, marking the boundaries of the range that could still contain the target. On each iteration:
- Compute the midpoint:
mid = floor((low + high) / 2). - Compare
arr[mid]to the target. - If equal, return
mid— found. - If
arr[mid]is smaller, the target must be to the right; setlow = mid + 1. - If
arr[mid]is larger, sethigh = mid - 1. - Repeat until found, or until
low > high(target absent).
The halving step is the magic. With a million-item array, the range halves to 500,000 → 250,000 → 125,000 → ... → 1 in just 20 comparisons. Linear search would average 500,000.
When to use binary search
- Your data is sorted, or you can afford to sort it once and search many times.
- You need an exact match, or the leftmost or rightmost match.
- Random-access reads are cheap (an array, not a linked list).
- You want predictable worst-case performance — binary search has no pathological inputs.
If your data changes constantly, the cost of keeping it sorted may outweigh the search savings. A hash table gives O(1) average lookups for unordered point queries. A balanced binary search tree gives O(log n) lookups and cheap ordered traversal.
Binary search vs linear search
| Linear search | Binary search | |
|---|---|---|
| Time complexity (worst) | O(n) | O(log n) |
| Requires sorted input | No | Yes |
| 1,000,000 items (worst case) | 1,000,000 comparisons | 20 comparisons |
| Best for | Tiny or unsorted arrays | Sorted arrays, repeated queries |
Linear search beats binary search only when the array is small (under roughly 30 elements, where the log-factor advantage is dwarfed by control overhead) or when the cost of sorting once exceeds the savings across all future queries.
Pseudo-code
function binarySearch(arr, target):
low = 0
high = arr.length - 1
while low <= high:
mid = floor((low + high) / 2)
if arr[mid] == target:
return mid
if arr[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1 # not found
JavaScript implementation
function binarySearch(arr, target) {
let low = 0;
let high = arr.length - 1;
while (low <= high) {
const mid = (low + high) >>> 1; // unsigned shift = safe integer divide
if (arr[mid] === target) return mid;
if (arr[mid] < target) low = mid + 1;
else high = mid - 1;
}
return -1;
}
The (low + high) >>> 1 trick avoids integer overflow on huge arrays — the same bug that lived in Java's standard library for nearly a decade before being fixed in 2006.
Python implementation
def binary_search(arr, target):
low, high = 0, len(arr) - 1
while low <= high:
mid = (low + high) // 2
if arr[mid] == target:
return mid
if arr[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
Python's standard library also offers bisect.bisect_left and bisect.bisect_right — implementations of the leftmost/rightmost variants that you should use in production rather than rolling your own.
Common bugs and edge cases
- Off-by-one in the loop condition. Use
low <= high, notlow < high— the latter misses the case wherelowandhighconverge on the target index. - Integer overflow on
(low + high). In languages with fixed-width integers, preferlow + (high - low) / 2or an unsigned shift. - Forgetting to update boundaries. Always set
low = mid + 1orhigh = mid - 1, notmid, or the loop spins forever. - Searching unsorted data. The algorithm returns garbage silently — there's no runtime check.
Frequently asked questions
Why is binary search O(log n)?
Each comparison eliminates half of the remaining search range. Halving an n-element range repeatedly takes log₂(n) steps. For n = 1,000,000, that's about 20.
Does binary search work on unsorted arrays?
No. The whole algorithm depends on knowing that items left of the midpoint are smaller and items right are larger. Without sorted order, halving the range tells you nothing useful.
Is binary search faster than a hash table?
For a single lookup in unsorted data, no — hash tables are O(1) average. But binary search wins when you need ordered queries (next-greater, range, leftmost match) or when the data is already sorted on disk.
What if the array contains duplicates?
Plain binary search returns any one matching index, undefined which. To find the leftmost or rightmost occurrence, modify the algorithm to keep searching one side after a match instead of returning immediately.
Can binary search work on a linked list?
Technically yes, but it's O(n log n) instead of O(log n) because each midpoint access requires traversal. Use a balanced BST or skip list for log-time search on linked structures.