Consider a sorted list comprising of 15 elements:
numList = [2,3,5,7,10,11,12,17,19,23,29,31,37,41,43]
We need to search for the key, say 17 in numList. The first, middle and last element identified in numList alongwith their index values are shown in Table 6.5.
| Index in numList | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| first | mid | last | |||||||||||||
| Value | 2 | 3 | 5 | 7 | 10 | 11 | 12 | 17 | 19 | 23 | 29 | 31 | 37 | 41 | 43 |
You're viewing a preview — the full solution, concept, methods & PYQ mapping are locked.
Start your 14-day free trial to unlock the full solution →Binary search works only on a sorted list. It compares the key with the middle element and throws away half the list at every step. For key = 17 in this 15-element list, mid = (0 + 14) // 2 = 7 and numList[7] is already 17 — found at index 7 in one comparison.
Concept understanding — why halving works
A linear search treats the list as an unordered heap: it must walk item by item. A sorted list carries extra information — if the middle element is bigger than the key, then every element to its right is bigger too, so the entire right half can be discarded without ever being looked at.
Each comparison therefore removes half of what is left:
| After comparison | Elements still in play (from 15) |
|---|---|
| 0 | 15 |
| 1 | 7 |
| 2 | 3 |
| 3 | 1 |
At most ⌈log₂(15 + 1)⌉ = 4 comparisons can ever be needed. That is the whole power of binary search — but it is bought entirely with the precondition that the list is sorted.
The three markers
| Marker | Meaning | Initial value for numList |
|---|---|---|
first | index of the first element of the active portion | 0 (value 2) |
last | index of the last element of the active portion | 14 (value 43) |
mid | (first + last) // 2 | 7 (value 17) |
This is exactly what Table 6.5 shows: first at index 0, mid at index 7, last at index 14.
Step-by-step trace — searching for the key 17
| Iteration | first | last | mid | numList[mid] | Comparison | Action taken |
|---|---|---|---|---|---|---|
| 1 | 0 | 14 | (0+14)//2 = 7 | 17 | 17 == 17 | Key found at index 7. Search ends. |
Only one comparison was needed. This is binary search's best case — the key happens to sit exactly at the first midpoint.
A contrasting trace — searching for the key 23
| Iteration | first | last | mid | numList[mid] | Comparison | Action taken |
|---|---|---|---|---|---|---|
| 1 | 0 | 14 | 7 | 17 | 23 > 17 | discard the left half → first = 8 |
| 2 | 8 | 14 | 11 | 31 | 23 < 31 | discard the right half → last = 10 |
| 3 | 8 | 10 | 9 | 23 | 23 == 23 | found at index 9 |
Three comparisons instead of the ten a linear search would have needed.
A failing search — the key 40
| Iteration | first | last | mid | numList[mid] | Comparison | Action |
|---|---|---|---|---|---|---|
| 1 | 0 | 14 | 7 | 17 | 40 > 17 | first = 8 |
| 2 | 8 | 14 | 11 | 31 | 40 > 31 | first = 12 |
| 3 | 12 | 14 | 13 | 41 | 40 < 41 | last = 12 |
| 4 | 12 | 12 | 12 | 37 | 40 > 37 | first = 13 |
| — | 13 | 12 | — | — | first > last | loop ends → not found (−1) |
The loop condition is while first <= last. When first overtakes last, the active portion is empty and the key is definitively absent. Writing < instead of <= would miss keys sitting in a one-element portion.
Program
def binary_search(numList, key):
first = 0
last = len(numList) - 1
comparisons = 0
while first <= last:
mid = (first + last) // 2
comparisons += 1
if numList[mid] == key:
return mid, comparisons
elif key < numList[mid]:
last = mid - 1 # search the left half
else: …
Unlock everything free for 14 days
- Full step-by-step solutions
- Concept-first explanations
- Methods, shortcuts & mistakes
- PYQ mapping + timed mock tests
Full access for 14 days. No credit card required.