Searching Algorithms
1. Linear Search
Section titled “1. Linear Search”Algorithm
Section titled “Algorithm”Problem: Given an array and a target value Determine whether exists in And return its index (or if not found).
def linear_search(A, x): for i in range(len(A)): if A[i] == x: return i return -1Correctness
Section titled “Correctness”Theorem. linear_search(A, x) returns the index of the first occurrence of in Or If is not present.
Proof. The algorithm examines elements in order. If It Immediately returns Which is the first occurrence since all earlier elements were checked and Found not equal to . If the loop completes without finding Then And is Returned.
Complexity Analysis
Section titled “Complexity Analysis”Theorem. Linear search has worst-case time complexity and best-case time complexity .
Proof of worst case. In the worst case, is at index or absent. The algorithm performs comparisons. Since each comparison takes time, the total is .
Proof of lower bound. Linear search requires comparisons in the worst case.
Proof. Consider an adversary argument. An adversary can answer “not equal” to the first Comparisons. Only after checking all elements can the algorithm conclude that is absent. Any Algorithm that does not check all positions can be fooled: the unchecked position could contain . Therefore, at least comparisons are necessary in the worst case.
| Case | Comparisons | Time |
|---|---|---|
| Best | 1 | |
| Average | ||
| Worst |
2. Binary Search
Section titled “2. Binary Search”Algorithm
Section titled “Algorithm”Problem: Given a sorted array and a target value Find the index of (or Determine that is not present).
def binary_search(A, x): low = 0 high = len(A) - 1 while low <= high: mid = (low + high) // 2 if A[mid] == x: return mid elif A[mid] < x: low = mid + 1 else: high = mid - 1 return -1Correctness Proof
Section titled “Correctness Proof”Theorem. binary_search(A, x) returns the index of in the sorted array Or if Is not present.
Proof. We prove by invariant.
Invariant: At the start of each loop iteration, if exists in Then .
Base case. Initially, low = 0 and high = n-1So . If The invariant holds.
Maintenance. Three cases:
- : Return mid. Correct. ✓
- : Since is sorted, So . Setting
low = mid + 1restricts the search to . If was in the old range, it is in the new range. - : Since is sorted, So . Setting
high = mid - 1restricts the search to . If was in the old range, it is in the new range.
Termination. The loop terminates when low > highMeaning is Empty. By the invariant, . Return . ✓
Complexity Analysis
Section titled “Complexity Analysis”Theorem. Binary search performs comparisons.
Proof. At each iteration, the search range is halved. Starting with a range of size After iterations the range size is at most . The algorithm terminates when the Range is empty, which happens when I.e., . Therefore, the maximum Number of iterations is .
Formal derivation. Let be the number of comparisons for an array of size .
By the Master Theorem (case 2): .
Theorem (Binary search lower bound). Any comparison-based search algorithm on a sorted array Requires comparisons in the worst case.
Proof. A decision tree for searching a sorted array of elements has at least leaves ( possible positions for Plus “not found”). A binary tree of height has at most leaves, so:
Example: Trace binary search for x = 7 in [1, 3, 5, 7, 9, 11, 13]
| Iteration | low | high | mid | A[mid] | Action |
|---|---|---|---|---|---|
| 1 | 0 | 6 | 3 | 7 | Found! Return 3 |
Result: index 3. ✓
Example: Trace binary search for x = 6 in [1, 3, 5, 7, 9, 11, 13]
| Iteration | low | high | mid | A[mid] | Action |
|---|---|---|---|---|---|
| 1 | 0 | 6 | 3 | 7 | 7 > 6, high = 2 |
| 2 | 0 | 2 | 1 | 3 | 3 < 6, low = 2 |
| 3 | 2 | 2 | 2 | 5 | 5 < 6, low = 3 |
| 4 | 3 | 2 | — | — | low > high, return -1 |
Result: -1 (not found). ✓
Recursive Binary Search
Section titled “Recursive Binary Search”def binary_search_recursive(A, x, low, high): if low > high: return -1 mid = low + (high - low) // 2 if A[mid] == x: return mid elif A[mid] < x: return binary_search_recursive(A, x, mid + 1, high) else: return binary_search_recursive(A, x, low, mid - 1)3. Comparison of Search Algorithms
Section titled “3. Comparison of Search Algorithms”| Property | Linear Search | Binary Search |
|---|---|---|
| Precondition | None | Array must be sorted |
| Best case | ||
| Average case | ||
| Worst case | ||
| Data structure | Array, list | Array (random access) |
| Works on linked list? | Yes | No (no random access) |
4. Variants
Section titled “4. Variants”Binary Search for Insertion Point
Section titled “Binary Search for Insertion Point”Find the position where should be inserted to maintain sorted order:
def binary_search_insert_position(A, x): low, high = 0, len(A) while low < high: mid = (low + high) // 2 if A[mid] < x: low = mid + 1 else: high = mid return lowBinary Search on a Answer Space
Section titled “Binary Search on a Answer Space”Binary search can be used to find a threshold in a continuous or discrete answer space (e.g., “minimum maximum”, “maximum minimum” problems).
Problem Set
Section titled “Problem Set”Problem 1. Trace linear search for the value 8 in the array [3, 1, 4, 1, 5, 9, 2, 6]. How many Comparisons are made?
Answer
The value 8 is not in the array. All 8 elements are checked:
| Step | Index | A[index] | Comparison | Count |
|---|---|---|---|---|
| 1 | 0 | 3 | 3 ≠ 8 | 1 |
| 2 | 1 | 1 | 1 ≠ 8 | 2 |
| 3 | 2 | 4 | 4 ≠ 8 | 3 |
| 4 | 3 | 1 | 1 ≠ 8 | 4 |
| 5 | 4 | 5 | 5 ≠ 8 | 5 |
| 6 | 5 | 9 | 9 ≠ 8 | 6 |
| 7 | 6 | 2 | 2 ≠ 8 | 7 |
| 8 | 7 | 6 | 6 ≠ 8 | 8 |
Total comparisons: 8. Return -1.
Problem 2. Trace binary search for the value 25 in the sorted array [2, 5, 8, 12, 16, 23, 38, 56, 72, 91]. Show all iterations.
Answer
| Iteration | low | high | mid | A[mid] | Action |
|---|---|---|---|---|---|
| 1 | 0 | 9 | 4 | 16 | 16 < 25, low = 5 |
| 2 | 5 | 9 | 7 | 56 | 56 > 25, high = 6 |
| 3 | 5 | 6 | 5 | 23 | 23 < 25, low = 6 |
| 4 | 6 | 6 | 6 | 38 | 38 > 25, high = 5 |
| 5 | 6 | 5 | — | — | low > high → -1 |
4 comparisons. Result: -1.
Problem 3. An array of 1024 elements is searched using binary search. What is the maximum number Of comparisons required?
Answer
comparisons.
More precisely, binary search on elements requires at most comparisons.
Problem 4. Prove that binary search cannot be directly applied to a singly linked list, and Explain what alternative approach could achieve search on a linked list.
Answer
Binary search requires access to the middle element (A[mid]). In a singly linked list, Accessing the -th element requires traversing nodes from the head, which is . Finding The middle of a list of elements takes time, eliminating the benefit of halving.
Alternative: Jump list / Skip list — a data structure with multiple levels of linked lists that Allows search by “skipping” ahead at higher levels, analogous to binary search.
Problem 5. Explain why the worst case for linear search is using an adversary Argument.
Answer
An adversary constructs the worst case dynamically. The adversary maintains that the target is Not at any position already examined by the algorithm. After comparisons, all positions Except one have been checked. The adversary places at the remaining unchecked position (or Declares it absent). Therefore, any correct algorithm must check all positions in the worst Case, requiring comparisons.
Problem 6. Write a function to count the number of occurrences of a value in a sorted array Using binary search. Your function should run in time.
Answer
Find the leftmost and rightmost occurrence using binary search, then compute the difference.
def count_occurrences(A, x): left = binary_search_insert_position(A, x) right = binary_search_insert_position(A, x + 1) - 1 if left <= right and left < len(A) and A[left] == x: return right - left + 1 return 0Two binary searches: .
Problem 7. Given an array that is sorted but rotated (e.g., [4, 5, 6, 7, 0, 1, 2]), write a Modified binary search that runs in time.
Answer
def search_rotated(A, x): low, high = 0, len(A) - 1 while low <= high: mid = (low + high) // 2 if A[mid] == x: return mid if A[low] <= A[mid]: if A[low] <= x < A[mid]: high = mid - 1 else: low = mid + 1 else: if A[mid] < x <= A[high]: low = mid + 1 else: high = mid - 1 return -1The key insight: one half of the array (left or right of mid) is always sorted. Determine which half Is sorted and whether the target lies within it.
Problem 8. A binary search implementation has the following bug: mid = (low + high) / 2 (using Floating-point division instead of integer division). What goes wrong?
Answer
In Python, / produces a float, and using a float as an array index raises a TypeError. In Languages like C/Java, int mid = (low + high) / 2 truncates toward zero, which works correctly for Positive values but is technically implementation-dependent.
The more serious bug is integer overflow: if low + high > INT_MAXThe sum overflows. The Correct form is mid = low + (high - low) / 2Which cannot overflow since high - low is always Non-negative and less than INT_MAX.
For revision on sorting, see Sorting Algorithms.
Problems
Section titled “Problems”Problem 1. Trace linear search for the value 14 in the array [7, 3, 14, 2, 9, 6, 1, 8]. How Many comparisons are made until the item is found?
Hint
Step through each element from index 0, comparing each with the target 14. Count each comparison Until a match is found.
Answer
| Step | Index | A[index] | Comparison | Count |
|---|---|---|---|---|
| 1 | 0 | 7 | 7 ≠ 14 | 1 |
| 2 | 1 | 3 | 3 ≠ 14 | 2 |
| 3 | 2 | 14 | 14 = 14 ✓ | 3 |
3 comparisons are made. The value 14 is found at index 2. The algorithm returns 2.
Problem 2. Trace linear search for the value 5 in the array [10, 20, 30, 40, 50, 60, 70, 80, 90]. How many comparisons are made?
Hint
The value 5 is not in the array, so the algorithm must check every single element before returning -1.
Answer
| Step | Index | A[index] | Comparison | Count |
|---|---|---|---|---|
| 1 | 0 | 10 | 10 ≠ 5 | 1 |
| 2 | 1 | 20 | 20 ≠ 5 | 2 |
| 3 | 2 | 30 | 30 ≠ 5 | 3 |
| 4 | 3 | 40 | 40 ≠ 5 | 4 |
| 5 | 4 | 50 | 50 ≠ 5 | 5 |
| 6 | 5 | 60 | 60 ≠ 5 | 6 |
| 7 | 6 | 70 | 70 ≠ 5 | 7 |
| 8 | 7 | 80 | 80 ≠ 5 | 8 |
| 9 | 8 | 90 | 90 ≠ 5 | 9 |
9 comparisons are made. The value 5 is not found, so the algorithm returns -1. This is the worst Case for an array of 9 elements — every element must be checked.
Problem 3. Trace binary search for the value 42 in the sorted array [3, 11, 19, 27, 35, 42, 50, 58, 66, 74]. Show all iterations with low, high, mid, and the action Taken.
Hint
Start with low = 0, high = 9. Calculate mid = (0 + 9) // 2 = 4. Compare A[4] with 42 and adjust the Range accordingly.
Answer
| Iteration | low | high | mid | A[mid] | Action |
|---|---|---|---|---|---|
| 1 | 0 | 9 | 4 | 35 | 35 < 42, low = 5 |
| 2 | 5 | 9 | 7 | 58 | 58 > 42, high = 6 |
| 3 | 5 | 6 | 5 | 42 | Found! Return 5 |
3 comparisons are made. The value 42 is found at index 5.
Problem 4. Trace binary search for the value 15 in the sorted array [2, 6, 10, 14, 18, 22, 26, 30]. Show all iterations.
Hint
The value 15 lies between 14 (index 3) and 18 (index 4). The algorithm will narrow down to this gap And then terminate with low > high.
Answer
| Iteration | low | high | mid | A[mid] | Action |
|---|---|---|---|---|---|
| 1 | 0 | 7 | 3 | 14 | 14 < 15, low = 4 |
| 2 | 4 | 7 | 5 | 22 | 22 > 15, high = 4 |
| 3 | 4 | 4 | 4 | 18 | 18 > 15, high = 3 |
| 4 | 4 | 3 | — | — | low > high, return |
4 comparisons are made. The value 15 is not in the array, so the algorithm returns -1.
Problem 5. An unsorted array of 10,000 elements must be searched repeatedly. Compare the total Cost of using linear search directly for 1,000 queries versus sorting the array once then using Binary search for 1,000 queries.
Hint
Calculate the cost of each approach: (a) 1,000 linear searches, and (b) one sort plus 1,000 binary Searches. Use O(n log n) for sorting and O(log n) for each binary search.
Answer
Linear search approach: 1,000 × O(10,000) = O(10,000,000) total comparisons.
Sort + binary search approach:
- One-time sort: O(10,000 log₂ 10,000) ≈ O(10,000 × 13.3) ≈ O(133,000) comparisons
- 1,000 binary searches: 1,000 × O(log₂ 10,000) ≈ 1,000 × 14 = O(14,000) comparisons
- Total: O(133,000) + O(14,000) = O(147,000) comparisons
Sort + binary search is approximately 68 times more efficient in total. The one-time cost of Sorting is quickly amortised over multiple queries. The more queries needed, the greater the Advantage of sorting first.
Problem 6. A database contains 500,000 records sorted by a unique key field. Explain which Search algorithm is more efficient and calculate the maximum number of comparisons for each Algorithm.
Hint
Since the data is already sorted, binary search can be applied directly. Calculate ⌊log₂(n)⌋ + 1 for The binary search worst case.
Answer
Linear search: Worst case = 500,000 comparisons. Time complexity: .
Binary search: Worst case = comparisons. Time Complexity: .
Binary search is dramatically more efficient — at most 19 comparisons versus 500,000 for linear Search, an improvement factor of approximately 26,000×. Since the data is already sorted, there is No additional preprocessing cost.
Problem 7. Calculate the maximum number of comparisons required for binary search on arrays of Sizes 15, 100, 500, and 1,000,000. Show your working using the formula .
Hint
Apply the formula to each array size. Remember that means the greatest integer less than or equal to .
Answer
Using :
| Max comparisons | |||
|---|---|---|---|
| 15 | 3.91 | 3 | 3 + 1 = 4 |
| 100 | 6.64 | 6 | 6 + 1 = 7 |
| 500 | 8.97 | 8 | 8 + 1 = 9 |
| 1,000,000 | 19.93 | 19 | 19 + 1 = 20 |
This demonstrates the power of logarithmic growth: searching through a million elements requires Only 20 comparisons maximum.
Problem 8. Write pseudocode for (a) a linear search that returns the index of the first Occurrence of a target value in an array, and (b) a binary search on a sorted array that returns the Index of the target or -1 if not found.
Hint
Linear search uses a simple FOR loop checking each element. Binary search uses a WHILE loop with low And high pointers, calculating mid each iteration.
Answer
(a) Linear search:
FUNCTION LinearSearch(A, x) FOR i ← 0 TO LEN(A) - 1 IF A[i] = x THEN RETURN i ENDIF ENDFOR RETURN -1ENDFUNCTION(b) Binary search:
FUNCTION BinarySearch(A, x) low ← 0 high ← LEN(A) - 1 WHILE low ≤ high mid ← (low + high) DIV 2 IF A[mid] = x THEN RETURN mid ELSE IF A[mid] < x THEN low ← mid + 1 ELSE high ← mid - 1 ENDIF ENDWHILE RETURN -1ENDFUNCTIONNote: In the binary search, DIV 2 performs integer division (floor division), which is equivalent To // in Python.
Problem 9. Trace binary search for the value 17 in the sorted array [4, 8, 12, 15, 17, 20, 24, 28, 32, 36, 40]. Show low, high, mid, and the comparison at each step.
Hint
The array has 11 elements (indices 0–10). Start with low = 0, high = 10. The first mid will be (0 + 10) // 2 = 5.
Answer
| Iteration | low | high | mid | A[mid] | Comparison | Action |
|---|---|---|---|---|---|---|
| 1 | 0 | 10 | 5 | 20 | 20 > 17 | high = 4 |
| 2 | 0 | 4 | 2 | 12 | 12 < 17 | low = 3 |
| 3 | 3 | 4 | 3 | 15 | 15 < 17 | low = 4 |
| 4 | 4 | 4 | 4 | 17 | 17 = 17 ✓ | Found! Return 4 |
4 comparisons are made. The value 17 is found at index 4.
Problem 10. (Exam-style) A school library system stores 20,000 book records. The librarian needs To: (a) search for a book by its ISBN (the catalogue is sorted by ISBN), (b) check whether a Specific book ID exists in an unsorted list of 50 recently returned books, (c) find the price of a Book given its ISBN in a sorted price catalogue. For each scenario, justify which search algorithm Is most appropriate, stating your assumptions about the data structure and ordering.
Hint
Consider three factors for each scenario: (1) Is the data sorted? (2) How large is the dataset? (3) How many searches will be performed? The cost of sorting must be weighed against the benefit of Binary search.
Answer
(a) Binary search. The ISBN catalogue is sorted and stored in an array with random access. Binary search requires at most comparisons, compared to 20,000 for linear search. This is efficient and appropriate since no preprocessing is needed.
(b) Linear search. The list of 50 recently returned books is unsorted and small. Linear search Takes at most 50 comparisons — negligible cost. Sorting first would cost Operations, which exceeds the 50 comparisons needed for a single search. For a single check, linear Search is optimal. If many repeated searches were needed, sorting first and using binary search (7 Comparisons max) would become worthwhile after approximately 6 searches ().
(c) Binary search. The price catalogue is sorted by ISBN with random access. Binary search finds The ISBN in comparisons, then retrieves the price at that index in . Linear search would require comparisons — unnecessary when the data is already Sorted.
Summary:
| Scenario | Data size | Sorted? | Best algorithm | Max comparisons |
|---|---|---|---|---|
| (a) ISBN lookup | 20,000 | Yes | Binary search | 15 |
| (b) Recently returned | 50 | No | Linear search | 50 |
| (c) Price lookup | 20,000 | Yes | Binary search | 15 |
Common Pitfalls
Section titled “Common Pitfalls”Forgetting that binary search requires a sorted array. Applying it to unsorted data gives incorrect results.
Confusing the number of comparisons with the number of elements examined in binary search.
Forgetting edge cases in algorithm design (e.g., empty input, single element, already sorted data).
Forgetting that average-case for quicksort becomes worst-case on already sorted input.
Misunderstanding the difference between a stack (LIFO) and a queue (FIFO) in data structure applications.
Confusing an algorithm with a program. An algorithm is a step-by-step procedure, not its implementation in code.
Common Mistakes
Section titled “Common Mistakes”Using binary search on an unsorted array. Binary search requires the array to be sorted. Applying it to unsorted data gives incorrect results because the comparison logic (discarding half the array) relies on the sorted order.
Confusing the mid calculation and causing integer overflow. Computing
mid = (low + high) // 2can overflow in languages with fixed-width integers whenlow + high > INT_MAX. The safe alternative ismid = low + (high - low) // 2.Forgetting that binary search on a linked list is not O(log n). Binary search requires O(1) random access to the middle element. Linked lists require O(n) traversal to reach the middle, making binary search O(n) — no better than linear search.
Not understanding why the worst case for linear search is Ω(n). An adversary can place the target at the last position checked or declare it absent. Any algorithm that doesn’t check all n positions can be fooled. This is a lower bound, not just an observation.
Miscounting comparisons in binary search traces. Each iteration of binary search involves exactly one comparison (A[mid] vs target). Students sometimes count multiple comparisons per iteration or forget that the loop termination condition itself is a comparison.
Summary
Section titled “Summary”The key principles covered in this topic are linked in the sub-pages above. Focus on understanding the definitions, applying the formulas or frameworks, and evaluating strengths and limitations of each approach.
Worked Examples
Section titled “Worked Examples”Worked examples demonstrating the application of key concepts are covered in the detailed sub-pages linked above.
Intuition
Section titled “Intuition”Searching is one of the most fundamental operations in computer science, and the two classic approaches — linear and binary search — illustrate a core trade-off: simplicity versus speed. Linear search is the obvious strategy: start at the beginning and check every item until you find what you are looking for. It works on any collection, sorted or not, but it is slow for large datasets because you might have to look at every single element. Binary search, by contrast, exploits order. By repeatedly halving the search space, it narrows down the target in logarithmic time — for a million items, it needs at most 20 comparisons instead of a million.
The key insight behind binary search is the power of eliminating half the possibilities at each step. Imagine looking up a word in a dictionary: you open it roughly in the middle, see whether your word comes before or after, and immediately discard half the pages. You repeat this until you find the word. This “divide and conquer” principle appears throughout computer science, from sorting algorithms to tree traversals. The catch is that binary search only works on sorted data, so if your data is not already ordered, you must pay the cost of sorting first — a decision that depends on how many searches you plan to perform.
In practice, the choice between algorithms depends on context. For small datasets, the overhead of binary search’s index management may not be worth it — linear search is simpler and fast enough. For large, frequently searched datasets, binary search (or its variants like interpolation search) is dramatically faster. Real-world systems often use hash tables for O(1) average-case lookups when exact matching is needed, or balanced binary search trees when both searching and ordered traversal are required. Understanding these trade-offs — data size, whether data is sorted, the cost of preprocessing, and the pattern of access — is what lets you choose the right tool for the job.