Algorithms: Linear & Binary Search
Searching is one of the most fundamental operations in computing. Linear search checks every element one by one. Binary search uses a "divide and conquer" strategy on sorted data to find items dramatically faster.
Learning Objectives
- 11.3.4.1 Implement linear search
- 11.3.4.2 Implement binary search
Conceptual Anchor
The Phone Book Analogy
Linear search = flipping through a phone book page by page from
start to finish. Works for any book, but slow.
Binary search = opening the
phone book to the middle, checking if name is before or after, then repeating
with the correct half. Much faster, but the book must be alphabetized.
Rules & Theory
Linear Search
def linear_search(lst, target):
"""Search for target in list. Return index or -1."""
for i in range(len(lst)):
if lst[i] == target:
return i # Found! Return the index
return -1 # Not found
# Example
numbers = [4, 7, 2, 9, 1, 5, 8]
result = linear_search(numbers, 9)
print(result) # 3 (index of 9)
result = linear_search(numbers, 6)
print(result) # -1 (not found)Binary Search
def binary_search(lst, target):
"""Search SORTED list for target. Return index or -1."""
low = 0
high = len(lst) - 1
while low <= high:
mid = (low + high) // 2
if lst[mid] == target:
return mid # Found!
elif lst[mid] < target:
low = mid + 1 # Search right half
else:
high = mid - 1 # Search left half
return -1 # Not found
# MUST be sorted!
numbers = [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
result = binary_search(numbers, 11)
print(result) # 5Comparison
| Feature | Linear Search | Binary Search |
|---|---|---|
| Data requirement | Any list (sorted or not) | Must be sorted! |
| Best case | 1 comparison (first element) | 1 comparison (middle element) |
| Worst case | n comparisons | log₂(n) comparisons |
| 100 elements | Up to 100 checks | At most 7 checks |
| 1,000,000 elements | Up to 1,000,000 checks | At most 20 checks! |
| Complexity | O(n) | O(log n) |
Why log₂?
Binary search halves the remaining items each step. For 1024 items: 1024 → 512 → 256 → 128 → 64 → 32 → 16 → 8 → 4 → 2 → 1. That's 10 steps = log₂(1024). Incredibly efficient!
Worked Examples
1 Binary Search Trace
# List: [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]
# Target: 23
# Step 1: low=0, high=9, mid=4 → lst[4]=16 < 23 → low=5
# Step 2: low=5, high=9, mid=7 → lst[7]=56 > 23 → high=6
# Step 3: low=5, high=6, mid=5 → lst[5]=23 == 23 → FOUND at index 5!
# Only 3 comparisons for a list of 10 items!| Step | low | high | mid | lst[mid] | Action |
|---|---|---|---|---|---|
| 1 | 0 | 9 | 4 | 16 | 16 < 23 → low = 5 |
| 2 | 5 | 9 | 7 | 56 | 56 > 23 → high = 6 |
| 3 | 5 | 6 | 5 | 23 | 23 == 23 → Found! |
2 Linear Search — Count Occurrences
def find_all(lst, target):
"""Find ALL positions of target in list."""
positions = []
for i in range(len(lst)):
if lst[i] == target:
positions.append(i)
return positions
data = [3, 7, 3, 2, 3, 8, 3]
result = find_all(data, 3)
print(f"Found at positions: {result}") # [0, 2, 4, 6]
print(f"Occurrences: {len(result)}") # 43 Search with Step Counter
def linear_search_counted(lst, target):
steps = 0
for i in range(len(lst)):
steps += 1
if lst[i] == target:
return i, steps
return -1, steps
def binary_search_counted(lst, target):
low, high, steps = 0, len(lst) - 1, 0
while low <= high:
steps += 1
mid = (low + high) // 2
if lst[mid] == target:
return mid, steps
elif lst[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1, steps
# Compare efficiency
import random
data = sorted(random.sample(range(10000), 1000))
target = data[750]
idx1, steps1 = linear_search_counted(data, target)
idx2, steps2 = binary_search_counted(data, target)
print(f"Linear: found at {idx1}, {steps1} steps") # ~751 steps
print(f"Binary: found at {idx2}, {steps2} steps") # ~10 stepsPitfalls & Common Errors
Binary Search on Unsorted Data
Binary search requires sorted data. Using it on an unsorted list gives wrong results or misses existing elements. Always sort first!
Off-by-One: low <= high
The while loop condition must be <= not <. With just
<, you miss the case where the target is the last remaining element (when low ==
high).
Integer Division for mid
Use // for mid calculation: mid = (low + high) // 2. Using
/ gives a float, which can't be used as an index.
Pro-Tips for Exams
Search Tips
- For exam trace tables: show
low,high,mid, andlst[mid]at each step - Maximum comparisons for binary search = ⌈log₂(n)⌉ + 1
- If the data is unsorted and you need one search → linear search
- If you'll search many times → sort once, then use binary search
- Python's
inkeyword does a linear search internally
Graded Tasks
What is the key requirement for binary search? What is the time complexity of each algorithm?
Why is binary search O(log n) while linear search is O(n)? Explain in your own words.
Trace binary search on [1, 3, 5, 7, 9, 11, 13] searching for 7. Show low, high, mid at each step.
Implement both linear and binary search, count the steps, and compare results for a list of 100 sorted numbers.
A sorted list has 1024 items. What is the maximum number of comparisons binary search needs? What about linear search?
Build a "number guessing game" that uses binary search strategy: the computer guesses your number in minimum steps.
Self-Check Quiz
mid = (low + high) // 2 calculate?