datarekha

Linear & Binary Search

Scan left-to-right in O(n), or halve a sorted range in O(log n) — and count the comparisons the way GATE does.

7 min read Beginner GATE DA Lesson 53 of 122

What you'll learn

  • Linear search scans left-to-right: O(n) worst, O(1) best, and needs no sorting
  • Binary search requires a sorted array and halves the range each comparison: O(log n)
  • Worst-case comparisons obey F(n) = F(floor(n/2)) + 1, about ceil(log2(n+1))
  • Why the comparison count is the recurrence's depth, not the sum of both halves

Before you start

The last lesson kept naming binary search as the hero of O(log n) — the halving that turns a million items into twenty comparisons. Now meet it properly, alongside its plodding cousin. Finding an item in a list has two textbook strategies, and the gap between them is the whole lesson. Linear search is the brute-force one: start at the left and check each element until you hit the target or fall off the end. Binary search is the clever one: if the array is already sorted, jump to the middle, decide whether the target lies left or right, and throw away half the array in a single comparison. Then repeat. The first is patient; the second is ruthless.

That “throw away half each time” is why binary search scales: one million sorted items need only about twenty comparisons, while a linear scan could need all million. The price of that speed — as we will see — is the one demand the last lesson hinted at.

Linear search — the baseline

Walk the array from index 0 rightward. The best case is a hit on the first element (O(1)); the worst case is the target sitting last or absent, forcing n comparisons (O(n)). Crucially, linear search needs no ordering — it works on any list, sorted or jumbled. That freedom is the trade: it asks nothing of the data, and in return it can promise nothing better than O(n).

Binary search — halving a sorted range

Keep two bounds, lo and hi, around the live range. Look at the middle element. If it equals the target you are done; if the target is larger, discard the left half (lo = mid + 1); if smaller, discard the right half (hi = mid - 1). Each comparison cuts the candidate count roughly in half — and that single act of discarding is the whole secret.

TryBinary search

Step through a binary search and watch it halve the range

Pick a target and press Play or Next.
0binary comparisons
up to 15linear worst case

Step through it and watch the comparison counter: the live range collapses n → n/2 → n/4 → … until one element (or none) remains. The number of halvings to get there is exactly what O(log n) measures.

Each comparison halves the live range1024512256128 → … → 11024 → 512 → 256 → 128 → … → 1 takes 10 halvings, so about log₂(1024) = 10.
A sorted array of 1024 halves ten times to reach a single element — the source of the O(log n) bound.

The worst-case comparison count satisfies a one-line recurrence: solve a problem of size n with one comparison plus a subproblem of half the size.

F(n)=F(⌊n/2⌋)+1one subproblem of half the sizeone comparison
With F(0) = 0, this solves to about ceil(log2(n+1)) comparisons — the recurrence’s depth.

Here is the algorithm in full, with a comparison counter, beside the recurrence computed directly — so you can see the two agree:

def binary_search(arr, target):
    lo, hi = 0, len(arr) - 1
    comparisons = 0
    while lo <= hi:                 # note: lo <= hi, not lo < hi
        comparisons += 1
        mid = (lo + hi) // 2
        if arr[mid] == target:
            return mid, comparisons
        elif arr[mid] < target:
            lo = mid + 1            # discard the left half
        else:
            hi = mid - 1            # discard the right half
    return -1, comparisons

# Worst-case comparisons via the recurrence F(n) = F(n//2) + 1
def F(n):
    return 0 if n == 0 else F(n // 2) + 1

print("F(1000) =", F(1000))
print("F(1024) =", F(1024))
print("F(1000000) =", F(1000000))

arr = list(range(1000))            # sorted 0..999
_, c = binary_search(arr, 10_000)  # absent target → worst case
print("comparisons to fail on n=1000:", c)

prints:

F(1000) = 10
F(1024) = 11
F(1000000) = 20
comparisons to fail on n=1000: 10

The empirical worst-case count (10 for n = 1000) matches the recurrence F(1000) = 10 exactly — the recurrence is not a guess, it is the algorithm’s depth.

How GATE asks this

The 2024 paper posed it as a NAT/MCQ on the recurrence itself: which relation gives the maximum number of comparisons binary search makes on n elements? The correct answer was option A, F(n) = F(⌊n/2⌋) + 1not the tempting F(⌊n/2⌋) + F(⌈n/2⌉). Binary search recurses into only one half, so you add a single comparison per level; you never explore both halves. The other classic form is a plain NAT: “max comparisons to search a sorted array of n items?”, answered with ⌈log₂(n+1)⌉ (equivalently ⌊log₂ n⌋ + 1).

Worked example — the 2024 recurrence

For binary search on a sorted array of n elements, write the recurrence for the maximum number of comparisons, then evaluate it for n = 1000.

The array of n costs one comparison at the middle, after which at most one half survives — a subproblem of size ⌊n/2⌋:

F(n) = F(⌊n/2⌋) + 1,   F(0) = 0

F(1000) = F(500) + 1
        = F(250) + 2
        = F(125) + 3
        = F(62)  + 4
        = F(31)  + 5
        = F(15)  + 6
        = F(7)   + 7
        = F(3)   + 8
        = F(1)   + 9
        = F(0)   + 10  =  10

So 10 comparisons, matching ⌈log₂(1000+1)⌉ = 10. A sorted array of exactly 1024 elements halves 1024 → 512 → 256 → … → 1 in ten steps — log₂(1024) = 10 — so binary search settles it in roughly ten comparisons too, against up to 1024 for a linear scan.

A question to carry forward

Binary search’s logarithmic speed comes with a non-negotiable price of admission, stated plainly in trap (1): the data must already be sorted. Linear search asks nothing of its input and pays O(n); binary search asks for order and is rewarded with O(log n). Which raises the obvious next question — where does that sorted array come from in the first place? Here is the thread onward: what are the simplest algorithms that take a jumbled list and put it in order, how do you trace them pass by pass, and what do they cost?

In one breath

  • Linear search: scan left-to-right; needs no ordering; best O(1), worst/average O(n).
  • Binary search: needs a sorted array; halve the live range each comparison → O(log n).
  • Worst-case comparisons obey F(n) = F(⌊n/2⌋) + 1 (one half, one comparison) ≈ ⌈log₂(n+1)⌉not F(⌊n/2⌋) + F(⌈n/2⌉).
  • Concretely: n = 100010, n = 10⁶20, n = 154 comparisons.
  • Traps: sorted-only, add 1 (don’t sum halves), loop condition lo <= hi.

Practice

Quick check

0/6
Q1Recall: which statements about linear vs binary search are TRUE? (select all that apply)select all that apply
Q2Recall: which recurrence gives the MAXIMUM number of comparisons made by binary search on n elements?
Q3Trace: on a sorted array of 15 elements, what is the maximum number of comparisons for binary search? (integer)numerical answer — type a number
Q4Apply: maximum number of comparisons binary search makes on a sorted array of 1000 elements? (integer)numerical answer — type a number
Q5Apply: a sorted array has 1,000,000 elements. At most how many comparisons does binary search need? (integer)numerical answer — type a number
Q6Create: an array is UNSORTED. Which statements are correct? (select all that apply)select all that apply

Sign in to track your progress

Completed lessons, your XP, level, and streak save to your account — it's free and takes a few seconds.

Practice this in an interview

All questions
Implement binary search correctly — and explain the off-by-one traps.

Binary search halves the search space each iteration to find a target in O(log n). The tricky part is not the idea but the boundary conditions: closed vs. half-open intervals, how to update lo/hi, and when to use lo < hi vs. lo <= hi. One clean template eliminates all the classic bugs.

Search for a target in a rotated sorted array in O(log n).

Even after rotation, one of the two halves around mid is always fully sorted. Check which half is sorted, then decide whether the target falls inside it. If yes, narrow to that half; if no, search the other. This keeps binary search's O(log n) guarantee.

Find the minimum eating speed for Koko to finish all bananas within h hours.

Binary search on the answer space (eating speed 1 through max pile size) rather than on the input array. For each candidate speed, greedily compute hours needed in O(n). The feasibility check is monotone — if speed k works, any speed above k also works — so binary search finds the minimum valid speed in O(n log m) time.

How does a B-tree index work, and when does the database choose not to use it?

A B-tree index stores key values in a balanced tree of sorted nodes, allowing the engine to reach any value in O(log n) page reads instead of scanning every row. The optimizer skips the index when the estimated cost of random I/O exceeds a full-table scan, when a function wraps the indexed column, or when the query returns such a large fraction of rows that a sequential scan is cheaper.

Related lessons

Explore further

Cheat sheets
Skip to content