I consider binary search one of the most elegant algorithms I have ever learned, precisely because of how much power it draws from a single assumption: that the data I am searching is sorted. Instead of checking elements one at a time, binary search repeatedly cuts the search space in half, comparing my target value against the middle element and discarding the half of the array that cannot possibly contain it. This gives me logarithmic-time search, a dramatic improvement over linear search, and it is a technique whose underlying idea — eliminating half the possibilities with each step — shows up again and again across computer science, well beyond just searching arrays.
History and Background
The earliest known reference to a binary search-like procedure dates back to 1946, when John Mauchly discussed the technique in a lecture as part of the Moore School Lectures on computing, one of the first formal courses on computer design and programming. The algorithm was formally published in 1962 by D.H. Lehmer, though correct implementations remained surprisingly elusive for decades — famously, Jon Bentley noted in his 1986 book Programming Pearls that most professional programmers’ implementations of binary search contained bugs, and it took until 1962 for the first published bug-free version to appear, with an integer overflow bug in the standard midpoint calculation persisting undetected in many textbooks and libraries (including Java’s own standard library) until it was identified and fixed in 2006.
Problem Statement
I need an efficient way to determine whether a target value exists within a large sorted collection, and if so, to find its position, without having to check every single element. Binary search solves this by exploiting the sorted order of the data: I can immediately rule out half of the remaining search space with a single comparison, giving me O(log n) time complexity instead of the O(n) required by a naive linear scan.
Core Concepts
- Sorted precondition: binary search only works correctly on data that is already sorted; it cannot be applied to unsorted collections without first sorting them.
- Search space: the current range of indices, bounded by
lowandhigh, that might still contain the target value. - Midpoint: the index roughly halfway between
lowandhigh, whose value is compared against the target to decide which half to discard. - Convergence: with each comparison, the search space shrinks by roughly half, guaranteeing the algorithm terminates in a logarithmic number of steps.
- Iterative vs. recursive: binary search can be implemented either with a loop (iterative) or with recursive function calls, with the iterative version generally preferred for its constant space usage.
How It Works
I follow these steps to search for a target value:
- I set
lowto the first index andhighto the last index of the array. - While
lowis less than or equal tohigh, I compute the midpoint index. - I compare the value at the midpoint with my target: if they are equal, I have found the target and return its index.
- If the target is smaller than the midpoint value, I discard the right half by setting
hightomid - 1. - If the target is larger, I discard the left half by setting
lowtomid + 1. - I repeat this process until I find the target or the search space becomes empty (
lowexceedshigh), in which case the target does not exist in the array.
Working Principle
The mechanism I rely on is that sorted order lets a single comparison eliminate an entire half of the remaining possibilities. Because the array is sorted, if my target is less than the middle element, I know with certainty it cannot exist anywhere to the right of the middle — every element there is guaranteed to be even larger. This certainty is what allows binary search to discard half the search space with just one comparison, rather than needing to check each discarded element individually. Repeating this halving process rapidly narrows the search space down to a single element or confirms the target’s absence.
Mathematical Foundation
If I start with n elements, after one comparison the search space shrinks to at most n/2 elements. After k comparisons, the search space size is:
$$\frac{n}{2^k}$$
The algorithm terminates when the search space shrinks to at most 1 element, so I solve for k:
$$\frac{n}{2^k} \leq 1 \implies 2^k \geq n \implies k \geq \log_2 n$$
This gives the time complexity:
$$T(n) = O(\log n)$$
This recurrence can also be expressed directly as:
$$T(n) = T\left(\frac{n}{2}\right) + O(1)$$
which, by the Master Theorem (with $a=1$, $b=2$, $f(n)=O(1)$), resolves to $T(n) = O(\log n)$.
Diagrams
flowchart TD
A["Start: low = 0, high = n - 1"] --> B{"Is low ≤ high?"}
B -- Yes --> D["mid = low + (high - low) / 2"]
B -- No --> C["Target not found"]
D --> E{"Is A[mid] = target?"}
E -- Yes --> F["Return mid (Target Found)"]
E -- No --> G{"Is A[mid] < target?"}
G -- Yes --> H["low = mid + 1"]
G -- No --> I["high = mid - 1"]
H --> B
I --> Bgraph LR
A["[2,4,6,8,10,12,14] target=10"] --> B["mid=8, 8<10, search right"]
B --> C["[10,12,14] mid=12, 12>10, search left"]
C --> D["[10] mid=10, found!"]
Pseudocode
BINARY-SEARCH(A, target)
low = 0
high = length(A) - 1
while low <= high
mid = low + (high - low) / 2
if A[mid] == target
return mid
else if A[mid] < target
low = mid + 1
else
high = mid - 1
return -1 // target not found
Step-by-Step Example
I will search for the target value 10 in the sorted array [2, 4, 6, 8, 10, 12, 14] (indices 0–6).
Step 1: low=0, high=6. mid = 0 + (6-0)/2 = 3. A[3] = 8. 8 < 10, so I discard the left half: low = 4.
Step 2: low=4, high=6. mid = 4 + (6-4)/2 = 5. A[5] = 12. 12 > 10, so I discard the right half: high = 4.
Step 3: low=4, high=4. mid = 4 + (4-4)/2 = 4. A[4] = 10. Match found! Return index 4.
Result: Target 10 found at index 4, after only 3 comparisons instead of up to 7 with a linear scan.
Time Complexity
- Best case: O(1) — occurs when the target happens to be exactly at the midpoint of the very first comparison.
- Average case: O(log n) — regardless of where the target lies (or if it’s absent), the search space is roughly halved with each step.
- Worst case: O(log n) — even when the target is not present at all, the search space still shrinks to zero in logarithmic time.
Space Complexity
The iterative version of binary search requires only O(1) additional space, since it just tracks low, high, and mid as simple variables. The recursive version requires O(log n) space due to the call stack, since each recursive call represents one level of the halving process. I generally prefer the iterative version in performance-sensitive code specifically to avoid this recursion overhead.
Correctness Analysis
I prove binary search correct using a loop invariant: at the start of every iteration, if the target exists in the array, it must lie within the current range A[low..high]. This holds trivially at the start, since the initial range covers the entire array. During each iteration, I compare the target to the midpoint value: if they match, I have found it and can return immediately; if the target is smaller, sortedness guarantees it cannot exist in A[mid+1..high], so narrowing the range to A[low..mid-1] preserves the invariant; symmetric reasoning applies if the target is larger. Since the search space strictly shrinks by at least one element with every iteration, the loop is guaranteed to terminate, and when it does — either by finding a match or by low exceeding high — the invariant guarantees the result is correct: either the target has been found, or it provably does not exist anywhere in the original array.
Advantages
- Extremely fast — O(log n) time complexity means even a billion-element array only needs about 30 comparisons.
- Simple to implement once the sortedness precondition is understood and respected.
- Requires only O(1) additional space in its iterative form.
- Forms the conceptual basis for many other efficient algorithms and techniques, including binary search on answer spaces (used in many optimization problems) and interpolation search.
Disadvantages
- Strictly requires the data to be sorted beforehand — if the data changes frequently, the cost of re-sorting can outweigh the benefit of fast searching.
- Not well suited to data structures without efficient random access, such as linked lists, where finding the midpoint itself takes O(n) time.
- Historically prone to a subtle integer overflow bug in the midpoint calculation (
(low + high) / 2) when low and high are both large, which is why I always preferlow + (high - low) / 2. - Less effective than hashing-based lookups (O(1) average case) when the data doesn’t need to remain sorted and only fast membership testing is required.
Applications
- Searching for values in sorted arrays or databases, such as looking up a specific record by a sorted key.
- Used in debugging tools like
git bisect, which uses binary search over a sequence of commits to find the one that introduced a bug. - Applied in numerical methods, such as finding roots of monotonic functions or solving optimization problems where the answer space itself can be binary searched.
- Used internally in many standard library functions (e.g.,
bsearchin C,Collections.binarySearchin Java) for fast lookups in sorted collections. - Applied in resource allocation and scheduling problems where a parameter needs to be tuned to satisfy a monotonic condition efficiently.
Implementation in C
#include <stdio.h>
// Iterative binary search implementation
int binarySearch(int arr[], int n, int target) {
int low = 0, high = n - 1;
while (low <= high) {
int mid = low + (high - low) / 2; // avoids overflow
if (arr[mid] == target) {
return mid; // target found
} else if (arr[mid] < target) {
low = mid + 1; // search right half
} else {
high = mid - 1; // search left half
}
}
return -1; // target not found
}
int main() {
int arr[] = {2, 4, 6, 8, 10, 12, 14};
int n = sizeof(arr) / sizeof(arr[0]);
int target = 10;
int result = binarySearch(arr, n, target);
if (result != -1) {
printf("Target %d found at index %d\n", target, result);
} else {
printf("Target %d not found in array\n", target);
}
return 0;
}
Sample Input and Output
Input: Sorted array [2, 4, 6, 8, 10, 12, 14], target = 10
Output: Target 10 found at index 4
Optimization Techniques
- I always compute the midpoint as
low + (high - low) / 2rather than(low + high) / 2to avoid integer overflow on very large arrays. - For data with a roughly uniform distribution, I use interpolation search instead, which estimates the likely position of the target rather than always splitting at the exact midpoint, achieving O(log log n) average time on uniformly distributed data.
- I use exponential (galloping) search combined with binary search when searching in an unbounded or very large sorted sequence, first finding a range that likely contains the target before binary searching within it.
- For repeated searches on the same static dataset, I consider building a more specialized structure, such as a hash table or a balanced binary search tree, if insertions and lookups both need to be fast.
Common Mistakes
- Applying binary search to unsorted data, which produces incorrect or unpredictable results since the core halving logic depends entirely on sortedness.
- Using
(low + high) / 2instead oflow + (high - low) / 2, risking integer overflow when low and high are both large numbers. - Getting the boundary updates wrong (
midinstead ofmid + 1ormid - 1), which can cause infinite loops when the search space no longer shrinks. - Using
<instead of<=in the while-loop condition, which can cause the algorithm to miss checking the very last remaining element. - Forgetting to handle duplicate values properly when the goal is to find the first or last occurrence of a target, rather than just any occurrence.
Further Reading
- Bentley, Jon, Programming Pearls, Addison-Wesley: https://www.pearson.com/en-us/subject-catalog/p/programming-pearls/P200000003428
- Cormen, Leiserson, Rivest, Stein, Introduction to Algorithms, MIT Press: https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/
- Bloch, Joshua, “Extra, Extra – Read All About It: Nearly All Binary Searches and Mergesorts are Broken,” Google Research Blog: https://research.google/blog/extra-extra-read-all-about-it-nearly-all-binary-searches-and-mergesorts-are-broken/
- GeeksforGeeks, “Binary Search”: https://www.geeksforgeeks.org/dsa/binary-search/
