Linear & Binary Search
Unordered scanning vs divide-and-conquer, 3 invariant formulations, avoiding integer overflow via mid = low + (high - low) / 2.
Reinforce your mental model: run, pause, and inspect live pointers with our interactive visualizer:
Topics Covered:
49. Linear Search (Sequential Search & Sentinel Optimization) • 50. Binary Search (Logarithmic Divide-and-Conquer Search)
Search algorithms represent computing's most fundamental query primitives, answering whether a target entity exists within a collection and identifying its precise location. The architectural approach to search hinges directly on the ordering invariants of the underlying data. Across unordered collections, exhaustive linear scanning is mathematically optimal without pre-indexing. When a collection is sorted, however, order permits the elimination of exponential fractions of the search space in each step. This chapter analyzes sequential linear search, sentinel loop optimizations, the divide-and-conquer mechanics of binary search, arithmetic integer overflow prevention, and formal loop invariants.
Learning Objectives
#- Formulate the fundamental search problem across arbitrary versus monotonically ordered sequences.
- Implement linear search and apply the sentinel optimization technique to eliminate per-iteration boundary checks.
- Master binary search's invariant-driven search interval halving and prevent 32-bit signed integer overflow.
- Derive the formal logarithmic recurrence using the Master Theorem.
- Trace binary search executions step-by-step using interval contraction state tracking.
Topic 49: Linear Search (Sequential Scanning)
#1. Problem Definition & Operational Mechanics
#Given an arbitrary array containing elements, determine whether a specified target value exists in . If found, return its zero-based index ; otherwise, return .
Linear Search inspects every cell sequentially from index to :
- Preconditions: Zero. Works across completely unordered collections, linked lists, files, and input streams.
- Decision Contract: Halts immediately on the first matching element.
Sequential Scan Trace: Target in
| Search Step | Inspected Index () | Element Value | Comparison vs Target () | Search State / Action Taken |
|---|---|---|---|---|
| 1 | 0 | 17 | Mismatch Advance index to | |
| 2 | 1 | 89 | Mismatch Advance index to | |
| 3 | 2 | 42 | MATCH FOUND! Return Index 2 |
2. Algorithmic Invariants & Complexity
#- Loop Invariant: At the beginning of iteration , the target element is guaranteed not to exist in the prefix subarray .
- Time Complexity:
- Best Case: (Target is located at index ).
- Average Case: (Assuming uniform probability distribution).
- Worst Case: (Target is at index or entirely absent).
- Auxiliary Space: (Only scalar iteration counter ).
3. Systems Optimization: Sentinel Linear Search
#Standard linear search incurs two branch comparisons on every single iteration:
- Loop boundary condition:
i < n - Value equality check:
A[i] == target
In high-throughput loops processing millions of records, branch predictor overhead degrades CPU pipelining. Sentinel Linear Search eliminates the boundary condition from the inner loop entirely:
- Temporarily store the original last element: .
- Overwrite the last element with the target: (acting as a guaranteed loop terminator).
- Scan using only the equality condition:
while A[i] != target: i++. - Restore .
- Check if or the restored last element matches the target.
FUNCTION SentinelLinearSearch(A: Array of Element, n: Integer, target: Element) -> Integer:
if n == 0:
return -1
last <- A[n - 1]
A[n - 1] <- target // Install sentinel
i <- 0
// Only ONE comparison per iteration: no i < n check!
while A[i] != target:
i <- i + 1
A[n - 1] <- last // Restore original element
if i < n - 1 or A[n - 1] == target:
return i
return -1Topic 50: Binary Search (Logarithmic Divide-and-Conquer)
#1. Conceptual Architecture & The Ordering Invariant
When an array is strictly sorted in non-decreasing order (), we can test the central element (). If the target does not match , order guarantees that an entire half of the remaining elements can be discarded immediately.
Initial Window: [ 2, 5, 8, 12, 16, 23, 38, 56, 72, 91 ] (Target = 23)
^ ^ ^
low mid high
A[mid] = 16 < 23 -> Discard left half entirely!
Next Window: [ 23, 38, 56, 72, 91 ]
^ ^ ^
low mid high
A[mid] = 56 > 23 -> Discard right half entirely!
Final Window: [ 23, 38 ] -> mid = 5: A[5] = 23 == Target Found!Interactive Simulation:
Step through interval contractions live in the Interactive Binary Search Simulator.
2. Implementation & The Integer Overflow Bug
#FUNCTION BinarySearch(A: Array of Element, n: Integer, target: Element) -> Integer:
low <- 0
high <- n - 1
while low <= high:
// Midpoint calculation avoiding integer overflow
mid <- low + (high - low) / 2
if A[mid] == target:
return mid
else if A[mid] < target:
low <- mid + 1
else:
high <- mid - 1
return -1⚠️ The Classic 32-Bit Integer Overflow Bug:
In many legacy textbooks, the midpoint formula is written as:mid = (low + high) / 2
In modern architectures processing large arrays (), iflow + highexceeds (), 32-bit signed addition overflows into a negative number, resulting in a negative array index and an instant runtime crash!
The Mathematically Sound Formula:
3. Step-by-Step Interval Contraction Trace
#Searching for target = 23 in ():
| Iteration | low | high | Calculated mid | Inspected Value | Comparison vs Target () | Search Window Update Action |
|---|---|---|---|---|---|---|
| 1 | 0 | 9 | 16 | Discard left half | ||
| 2 | 5 | 9 | 56 | Discard right half | ||
| 3 | 5 | 6 | 23 | Target Located! Return Index 5 |
4. Mathematical Complexity Proof
#At each iteration, the remaining search window is halved:
- Initial interval size:
- After iteration 1:
- After iteration 2:
- After iteration :
The algorithm terminates when the search interval size is reduced to 1 element ():
Scaling Differential: Linear vs. Binary Search Comparisons
| Collection Size () | Linear Search (Worst-Case Comparisons) | Binary Search (Worst-Case Comparisons ) |
|---|---|---|
| () | ||
| () | () | () |
5. Key Takeaways
#- Unsorted Generality: Linear search requires zero preconditions, operating across arbitrary streams in time.
- Sentinel Optimization: Placing a temporary copy of the target at array end eliminates the
i < nloop boundary branch. - Logarithmic Scaling: Binary search halves the remaining search space at every comparison, achieving performance across sorted containers.
- Overflow Prevention: Always compute midpoint as to avoid signed integer wraparound.
Academic Attribution & References
#- Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2022). Introduction to Algorithms (4th ed.), Section 2.3 & Chapter 12. MIT Press.
- Bentley, J. (2000). Programming Pearls (2nd ed.), Column 4: Writing Correct Programs. Addison-Wesley.
- Knuth, D. E. (1998). The Art of Computer Programming, Volume 3: Sorting and Searching (2nd ed.), Section 6.2: Searching by Comparison of Keys. Addison-Wesley.
- Bloch, J. (2006). Extra, Extra - Read All About It: Nearly All Binary Searches and Mergesorts are Broken. Google Research Blog.