Linear & Binary Search
Learn linear and binary search algorithms in Python: step-by-step walkthrough, hands-on exercise, troubleshooting, and what to study next.
Focus: linear and binary search python
You have a sorted list of a million customer IDs and need to find one. Looping through every single entry is painfully slow — a linear search checks each element one by one, which becomes unbearable at scale. Instead, binary search can locate the target in a fraction of the steps by repeatedly dividing the search space in half. Understanding both algorithms is crucial because picking the wrong one can mean the difference between a response in milliseconds and one that times out.
The problem this lesson solves
Any time you need to find an item in a collection, you face a core computer science challenge. Without a structured approach, you might write a simple for loop — that's linear search. It works, but its time complexity is O(n). For a list with 1,000 elements, that's up to 1,000 checks. For 1,000,000 elements, it's up to 1,000,000 checks.
Binary search solves this by operating only on sorted data. It achieves O(log n) time complexity: for the same million-element list, it requires at most 20 checks. The catch? Your data must be sorted first. This lesson teaches you both algorithms so you can make the right trade-off for your use case.
Core concept / mental model
Think of linear search like flipping through every page of a phone book to find a name — you start at page 1 and read every single entry. It’s simple but slow.
Binary search is smarter: you open the phone book to the middle. If the name you're looking for comes after that page, you discard the entire first half. Then you repeat with the remaining half, each time cutting your search space in half. You keep doing this until you find the name or conclude it isn't there.
Key insight: Linear search works on any list (sorted or unsorted). Binary search requires a sorted list but is exponentially faster on large datasets.
When to use each
- Linear search: small lists (under ~100 items), unsorted data, or when you need to find the first occurrence quickly.
- Binary search: large sorted datasets, repeated searches, or when you can afford a one-time sort upfront.
How it works step by step
Linear search (sequential search)
- Start at the first element (index 0).
- Compare the current element to the target value.
- If it matches, return the current index.
- If it doesn't match, move to the next element.
- Repeat until you find the target or reach the end of the list.
- If you reach the end without a match, return
-1(orNone).
Binary search (divide and conquer)
- Precondition: the list is sorted in ascending order.
- Set two pointers:
low = 0andhigh = len(list) - 1. - While
low <= high:- Calculate
mid = (low + high) // 2. - Compare
list[mid]with the target:- Equal: return
mid. - Greater than target: set
high = mid - 1(search left half). - Less than target: set
low = mid + 1(search right half).
- Equal: return
- Calculate
- If the loop ends without returning, the target is not present — return
-1.
Hands-on walkthrough
Let's implement both algorithms in Python.
1. Linear search function
def linear_search(arr, target):
"""Return index of target in arr, or -1 if not found."""
for i in range(len(arr)):
if arr[i] == target:
return i
return -1
# Example usage
numbers = [3, 7, 2, 9, 5, 1, 8]
print(linear_search(numbers, 5)) # Output: 4
print(linear_search(numbers, 10)) # Output: -1
2. Binary search (iterative)
def binary_search(arr, target):
"""Return index of target in sorted arr, or -1 if not found."""
low, high = 0, len(arr) - 1
while low <= high:
mid = (low + high) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
low = mid + 1
else:
high = mid - 1
return -1
# Example usage on a sorted list
sorted_numbers = [1, 3, 5, 7, 9, 11, 13]
print(binary_search(sorted_numbers, 7)) # Output: 3
print(binary_search(sorted_numbers, 4)) # Output: -1
3. Binary search (recursive)
def binary_search_recursive(arr, target, low, high):
"""Recursive version of binary search."""
if low > high:
return -1
mid = (low + high) // 2
if arr[mid] == target:
return mid
elif arr[mid] < target:
return binary_search_recursive(arr, target, mid + 1, high)
else:
return binary_search_recursive(arr, target, low, mid - 1)
arr = [1, 3, 5, 7, 9]
# Initial call: low = 0, high = len(arr)-1
print(binary_search_recursive(arr, 7, 0, len(arr)-1)) # Output: 3
Pro tip: The recursive version is elegant but may hit recursion limits on very large arrays. The iterative version is generally preferred in production.
Compare options / when to choose what
| Feature | Linear Search | Binary Search |
|---|---|---|
| Requires sorted data? | No | Yes |
| Time complexity | O(n) | O(log n) |
| Space complexity | O(1) | O(1) iterative, O(log n) recursive |
| Best for | Small/unsorted datasets | Large sorted datasets |
| Performance on 1M | Up to 1M comparisons | Max ~20 comparisons |
When to choose: - Linear search when: data is small (under ~50-100 items), data is frequently changing/unsorted, or you need a quick throwaway solution. - Binary search when: the dataset is large, you can sort once and search often, or performance is critical.
Variation: Interpolation search is a smarter binary search that guesses the position based on value distribution (like opening a dictionary near the letter 'M' when looking for 'Mango'). It can be even faster than binary search on uniformly distributed data but has O(n) worst-case.
Troubleshooting & edge cases
| Common Mistake | How to Fix |
|---|---|
| Forgetting to sort before binary search | Always call arr.sort() or work with a sorted copy. |
Off-by-one errors in mid calculation |
Use mid = (low + high) // 2 (integer division). Avoid (low + high) // 2 overflow issue in other languages, but Python's big ints are safe. |
| Not handling empty lists | Both functions should return -1 for empty input. Add a guard: if not arr: return -1. |
Confusing low and high bounds |
Ensure low starts at 0 and high at len(arr)-1. The loop condition is low <= high. |
| Recursive stack overflow on huge sorted list | Use iterative binary search for very large arrays (depth of recursion ~ log n, but Python's default recursion limit is 1000). |
Edge case: duplicate elements
- Linear search: returns the first occurrence (lowest index).
- Binary search: may return any occurrence — it’s not guaranteed to be the first. If you need the first occurrence, do a left-biased binary search.
def leftmost_binary_search(arr, target):
"""Return the first (leftmost) index of target in sorted arr."""
low, high = 0, len(arr) - 1
result = -1
while low <= high:
mid = (low + high) // 2
if arr[mid] == target:
result = mid
high = mid - 1 # keep searching left
elif arr[mid] < target:
low = mid + 1
else:
high = mid - 1
return result
What you learned & what's next
You now understand the two fundamental search algorithms in computer science. You can:
- Explain how linear search checks every element (O(n)) and works on unsorted data.
- Explain how binary search cuts the search space in half each step (O(log n)) and requires sorted data.
- Implement both algorithms in Python, including handling edge cases like empty lists and duplicates.
- Choose the right algorithm based on dataset size, sort order, and performance requirements.
Next up: Sorting algorithms — like bubble sort, merge sort, and quicksort — which are the natural companion to binary search. After all, binary search is only as fast as your ability to keep data sorted!
Practice recap
Try implementing a small program that asks the user for a number, then searches for it in a randomly generated sorted list of 1,000 integers. Compare the number of steps linear search vs binary search takes.
Bonus challenge: Modify the binary search function to return the first occurrence of a duplicate target (leftmost binary search). Verify it works by searching for a value that appears multiple times.
Common mistakes
- Forgetting to sort the list before using binary search — binary search on unsorted data will likely return incorrect results or never find the target.
- Off-by-one errors in the
midcalculation or loop condition (using < instead of <=), leading to infinite loops or missed results. - Using recursive binary search on very large lists that cause Python's recursion depth limit to be exceeded (max ~1000).
- Not correctly handling the case when the target is smaller than all elements or larger than all elements — the loop exits cleanly only if bounds are set correctly.
Variations
- Interpolation search: improves binary search by guessing the position based on value distribution (e.g., dictionary search). Best for uniformly distributed data.
- Exponential search: starts with a small range and exponentially expands it until the target is within range, then does a binary search. Useful for unbounded or infinite lists.
- Ternary search: divides the search space into three parts (instead of two) — usually slower than binary search due to more comparisons.
Real-world use cases
- Finding a user by their ID in a sorted database table — binary search makes lookups near-instant for millions of records.
- Implementing autocomplete suggestions: using binary search on a sorted dictionary of words to find all matches with a given prefix.
- Searching for a specific line in a large sorted log file without loading the entire file into memory — a variant of external binary search.
Key takeaways
- Linear search checks every element (O(n)) and works on any list, sorted or not.
- Binary search requires a sorted list but runs in O(log n) — exponentially faster on large datasets.
- The iterative version of binary search is usually safer than the recursive one to avoid stack overflow.
- Always sort your data before calling binary search — forgetting this is the most common error.
- Use binary search when you can afford the sort upfront and need repeated lookups; use linear search for small or unsorted data.
- Python's built-in
bisectmodule provides a robust, optimized implementation of binary search — prefer it for production code.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.