Binary search finds a target value in a sorted sequence by repeatedly dividing the search space in half. At each step, it compares the target with the middle element and discards half of the remaining elements.
This reduces the problem size exponentially, which leads to logarithmic time complexity.
Problem
Given a sorted array of length and a value , find an index such that
If no such index exists, return .
Key Idea
Maintain a search interval . At each step:
- Compute midpoint
- Compare with
- Eliminate half of the interval
Algorithm
binary_search(A, x):
l = 0
r = length(A) - 1
while l <= r:
m = l + (r - l) // 2
if A[m] == x:
return m
else if A[m] < x:
l = m + 1
else:
r = m - 1
return -1Example
Let
and
Steps:
| step | l | r | m | A[m] | action |
|---|---|---|---|---|---|
| 1 | 0 | 5 | 2 | 5 | move right |
| 2 | 3 | 5 | 4 | 9 | move left |
| 3 | 3 | 3 | 3 | 7 | found |
Return index .
Correctness
At each step, the algorithm maintains the invariant:
- If exists in , then it must lie within
Each comparison removes half of the remaining candidates while preserving this invariant. When , the interval is empty, so does not exist.
Complexity
| case | comparisons | time |
|---|---|---|
| best | ||
| worst | ||
| average |
Space complexity:
- Iterative:
- Recursive: due to call stack
Requirements
Binary search requires:
- The array must be sorted
- Random access to elements
If either condition fails, correctness or efficiency breaks.
Common Variants
Binary search generalizes to:
- Lower bound (first )
- Upper bound (first )
- First true in monotone predicate
- Search on answer space
These variants rely on the same invariant: monotonicity.
Implementation
def binary_search(a, x):
l, r = 0, len(a) - 1
while l <= r:
m = l + (r - l) // 2
if a[m] == x:
return m
elif a[m] < x:
l = m + 1
else:
r = m - 1
return -1func BinarySearch(a []int, x int) int {
l, r := 0, len(a)-1
for l <= r {
m := l + (r-l)/2
if a[m] == x {
return m
} else if a[m] < x {
l = m + 1
} else {
r = m - 1
}
}
return -1
}