Python Binary Search Program (Iterative and Recursive)
-1.If you look up a word in a printed dictionary, you do not read it from page one. You open it near the middle, decide whether your word comes before or after, and repeat on the correct half. Binary search does exactly that with a list.
The one hard rule: the list must already be sorted. On unsorted data the answer is meaningless. If your data is unsorted and you search it only once, linear search is simpler and just as good; if you will search many times, sort once and then use binary search.
| Input | A sorted list and a target value |
|---|---|
| Output | Index of the target, or -1 if it is missing |
| Approach | Keep a low and high boundary, test the middle, halve the range each time |
| Time complexity | O(log n); O(1) extra space for the iterative version |
Approach: binary search step by step
- Set
low = 0andhigh = len(items) - 1. - While
low <= high, computemid = (low + high) // 2. - If
items[mid]equals the target, returnmid. - If
items[mid]is smaller than the target, the target can only be to the right, so setlow = mid + 1. - Otherwise it can only be to the left, so set
high = mid - 1. - When the loop ends with
low > high, the range is empty: return-1.
Each pass throws away half of the remaining items. A list of 1,000,000 items needs at most about 20 comparisons.
How the binary search code works
The loop condition low <= high means "there is still at least one item to look at". The floor division // (see Python numbers) keeps mid an integer. The + 1 and - 1 are essential: mid has already been checked, so moving the boundary past it guarantees the range shrinks every iteration and the while loop always ends.
Watch the boundaries move for the target 23:
items = [2, 5, 8, 12, 16, 23, 38, 56]
low, high = 0, len(items) - 1
while low <= high:
mid = (low + high) // 2
print("low", low, "high", high, "mid", mid, "value", items[mid])
if items[mid] == 23:
break
elif items[mid] < 23:
low = mid + 1
else:
high = mid - 1Binary search with bisect and recursion
The standard library module bisect implements the hard part. bisect_left(items, target) returns the position where the target is, or would be inserted to keep the list sorted, so you only need to confirm the item is really there. A recursive version is also possible (it follows the same idea as recursion), but the loop is usually clearer and avoids deep call stacks.
Binary search vs linear search
| Aspect | Linear search | Binary search |
|---|---|---|
| List must be sorted? | No | Yes |
| Worst-case comparisons | n | about log2(n) |
| Time complexity | O(n) | O(log n) |
| Best for | Small or unsorted lists | Large sorted lists searched often |
| Code complexity | Very simple | Easy to get boundaries wrong |
Examples you can run
Press Run, then edit the code and run it again.
Iterative binary search on sorted scores
The program finds an existing value and reports -1 for a missing one.
def binary_search(items, target):
low = 0
high = len(items) - 1
while low <= high:
mid = (low + high) // 2
if items[mid] == target:
return mid
elif items[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
scores = [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]
print(binary_search(scores, 23))
print(binary_search(scores, 2))
print(binary_search(scores, 91))
print(binary_search(scores, 40))Expected output5
0
9
-1
Alternative: binary search with bisect
bisect_left does the halving in fast C code. Check bounds before comparing, because the insertion point can equal len(items).
from bisect import bisect_left
def search(items, target):
pos = bisect_left(items, target)
if pos < len(items) and items[pos] == target:
return pos
return -1
prices = [99, 149, 249, 399, 799]
print(search(prices, 249))
print(search(prices, 300))
print(search(prices, 1000))Expected output2
-1
-1
Edge cases: empty list, one item and duplicates
With duplicates binary search may return any matching index, not necessarily the first one.
def binary_search(items, target):
low = 0
high = len(items) - 1
while low <= high:
mid = (low + high) // 2
if items[mid] == target:
return mid
elif items[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
print(binary_search([], 7))
print(binary_search([7], 7))
print(binary_search([7], 3))
print(binary_search([1, 2, 2, 2, 3], 2))Expected output-1
0
-1
2
Interactive lookup of a product code
The user types a number and the program searches a sorted list of product codes. int() converts the typed text first (see converting strings to int).
def binary_search(items, target):
low = 0
high = len(items) - 1
while low <= high:
mid = (low + high) // 2
if items[mid] == target:
return mid
elif items[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
codes = [101, 205, 310, 422, 518, 640, 777]
code = int(input("Product code: "))
position = binary_search(codes, code)
if position == -1:
print("Code not found")
else:
print("Found at index", position)Expected outputProduct code: 518
Found at index 4
Common mistakes
Searching an unsorted list
✗ Wrong
def binary_search(items, target):
low, high = 0, len(items) - 1
while low <= high:
mid = (low + high) // 2
if items[mid] == target:
return mid
elif items[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
print(binary_search([9, 1, 7, 3, 5], 1))✓ Right
def binary_search(items, target):
low, high = 0, len(items) - 1
while low <= high:
mid = (low + high) // 2
if items[mid] == target:
return mid
elif items[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
print(binary_search(sorted([9, 1, 7, 3, 5]), 1))Sort the list first with sorted(items) (see sorting), or use linear search for unsorted data.
Forgetting the +1 / -1 when moving boundaries
✗ Wrong
low = 0
high = 4
items = [1, 2, 3, 4, 5]
target = 9
while low <= high:
mid = (low + high) // 2
if items[mid] < target:
low = mid
else:
high = mid✓ Right
low = 0
high = 4
items = [1, 2, 3, 4, 5]
target = 9
while low <= high:
mid = (low + high) // 2
if items[mid] < target:
low = mid + 1
else:
high = mid - 1
print("done")Use low = mid + 1 and high = mid - 1, since mid has already been compared.
Python Binary Search Program (Iterative and Recursive): questions people ask
Why must the list be sorted for binary search?
Binary search discards half of the list based on one comparison, which is only valid if everything left of the middle is smaller and everything right of it is larger. On an unsorted list that assumption is false and the result is wrong.
What is the time complexity of binary search?
Binary search is O(log n) because the search range is halved every step. Searching 1,000,000 sorted items takes at most about 20 comparisons.
Is there a built-in binary search in Python?
Yes: the bisect module in the standard library. bisect_left() and bisect_right() find the insertion point in a sorted list using binary search.
Keep learning
Step-by-step lessons:
Python while LoopsPython ListsPython Sorting
Related:
Python Program for Linear Search (with Examples)Python sorted() FunctionPython Bubble Sort Program (with Explanation)Python Recursion
More in algorithms:
Python Program for Linear Search (with Examples)Python Bubble Sort Program (with Explanation)Python Selection Sort Program (with Explanation)Python Tower of Hanoi Program (Recursion Explained) See all →