G27
Self-checkedTier 1 16 min readalgo.searching-linear-binary

Linear and binary search

Finding a key in a collection: linear search and its best, worst and average cost, binary search on a sorted array with its invariant, the exact worst case floor(log2 n) + 1, why this is optimal, the midpoint overflow, the first-occurrence variant, and why binary search needs both order and random access.

Why it exists

Almost every program needs to find things: a record by its key, a word in a dictionary, a value in a table. How fast this can be done depends on what is known about the collection. If nothing is known, every element may have to be looked at. If the elements are sorted and can be reached by position, each look can throw away half of what remains, and a million elements need only 20 looks. This page shows both ends, and the reason the second needs two assumptions (order and direct access), which is what exam questions test.

Prerequisites

You need to count the steps of a loop (analysing loops) and to know that an array gives direct access to any position (arrays).

Precise definitions

Search problem. Given a collection a0,…,an−1a_0, \ldots, a_{n-1} and a key xx, report a position ii with ai=xa_i = x, or report that there is none. A search is successful if the key is present and unsuccessful otherwise.

Linear (sequential) search. Examine a0,a1,…a_0, a_1, \ldots in order until the key is found or the end is reached. It needs no assumption about the collection and works on arrays and on linked lists.

Binary search. For an array sorted in increasing order, keep a range alo,…,ahia_{lo}, \ldots, a_{hi} that contains every position where the key could still be. Examine the middle element amida_{mid}; if it equals the key, stop; if it is smaller than the key, the key can only be to the right, so set lo=mid+1lo = mid + 1; otherwise set hi=mid−1hi = mid - 1. Stop when the range is empty.

Invariant. If the key is in the array at all, its position is in [lo,hi][lo, hi]. It is true at the start (lo=0lo = 0, hi=n−1hi = n - 1), each step keeps it true (because the array is sorted), and when the loop ends with lo>hilo > hi the range is empty, so the key is absent. The range at least halves each time, which is why the loop ends.

Probe. One examination of an array element. Binary search makes one probe per iteration. The C code below uses two tests per probe (== and <), but they are one three-way comparison of the key with amida_{mid} (less, equal, greater). Exam questions count either probes or three-way comparisons, which are the same number; if a question counts every == and < separately it will say so.

Costs. For linear search the best case is 11 probe, the worst case is nn, and for a successful search with the key equally likely at each position the average is (n+1)/2(n+1)/2. For binary search the best case is 11 and the worst case is ⌊log⁡2n⌋+1\lfloor \log_2 n \rfloor + 1 probes (equivalently ⌈log⁡2(n+1)⌉\lceil \log_2 (n + 1) \rceil).

How it works

Both searches in C. They are the code that produced the numbers below; probes counts the array elements examined.

#include <stdio.h>
 
/* both return the index of key or -1; *probes receives the number of array elements examined */
static int linear_search(const int a[], int n, int key, int *probes) {
    *probes = 0;
    for (int i = 0; i < n; i++) {
        (*probes)++;
        if (a[i] == key) return i;
    }
    return -1;
}
 
static int binary_search(const int a[], int n, int key, int *probes) {
    int lo = 0, hi = n - 1;
    *probes = 0;
    while (lo <= hi) {
        int mid = lo + (hi - lo) / 2;
        (*probes)++;
        if (a[mid] == key) return mid;
        if (a[mid] < key) lo = mid + 1;
        else hi = mid - 1;
    }
    return -1;
}
 
int main(void) {
    int sizes[] = {1, 3, 7, 8, 15, 16, 100, 1000};
    static int a[1000];
    printf("%5s %9s %9s %7s %9s %7s %6s\n", "n", "lin-hit", "bin-hit", "bin-max", "bin-miss", "miss-max", "bound");
    for (int s = 0; s < 8; s++) {
        int n = sizes[s], p;
        long lin_hit = 0, bin_hit = 0, bin_miss = 0;
        int hit_max = 0, miss_max = 0;
        for (int i = 0; i < n; i++) a[i] = 2 * i;            /* the keys are 0, 2, 4, ... */
        for (int i = 0; i < n; i++) {                        /* every successful search, once */
            linear_search(a, n, 2 * i, &p);
            lin_hit += p;
            binary_search(a, n, 2 * i, &p);
            bin_hit += p;
            if (p > hit_max) hit_max = p;
        }
        for (int g = 0; g <= n; g++) {                       /* every unsuccessful search: -1, 1, 3, ..., 2n - 1 */
            binary_search(a, n, 2 * g - 1, &p);
            bin_miss += p;
            if (p > miss_max) miss_max = p;
        }
        int bound = 0;
        for (int m = n; m > 0; m /= 2) bound++;              /* floor(log2 n) + 1 */
        printf("%5d %9ld %9ld %7d %9ld %7d %6d\n", n, lin_hit, bin_hit, hit_max, bin_miss, miss_max, bound);
    }
    return 0;
}
    n   lin-hit   bin-hit bin-max  bin-miss miss-max  bound
    1         1         1       1         2       1      1
    3         6         5       2         8       2      2
    7        28        17       3        24       3      3
    8        36        21       4        29       4      4
   15       120        49       4        64       4      4
   16       136        54       5        70       5      5
  100      5050       580       7       680       7      7
 1000    500500      8987      10      9987      10     10

Read the columns for each nn (the keys are 0,2,4,…0, 2, 4, \ldots, so every odd number is an unsuccessful search):

  • lin-hit is the total number of probes of linear search over all nn successful searches: 1+2+⋯+n=n(n+1)/21 + 2 + \cdots + n = n(n+1)/2, so the average is (n+1)/2(n+1)/2. An unsuccessful linear search always examines all nn elements.
  • bin-hit and bin-miss are the totals of binary search over all nn successful and all n+1n + 1 unsuccessful searches. For n=1000n = 1000 a successful search takes 8987/1000≈98987/1000 \approx 9 probes on average.
  • bin-max and miss-max are the worst cases, and bound is ⌊log⁡2n⌋+1\lfloor \log_2 n \rfloor + 1. They agree in every row, for present and for absent keys.

Probes of linear and binary search, measured: start

Computed by a script, not typed
nlinear: average probes (hit)linear: probes (miss)binary: average probes (hit)binary: worst probes (hit)binary: worst probes (miss)floor(log2 n) + 1
1
3
7
8
15
16
100
1000

Step 0

Every successful search (each key once) and every unsuccessful search (each gap once) was run on sorted arrays of n keys, counting the array elements examined. The numbers come from the C program on this page.

0 / 8
computed by script: the quantities are measured by running C, or evaluated, one row at a time. python3 scripts/gen-algo-sort-traces.py

The animation. The code is binary_search from the page, run for real: faded positions are ruled out. The first search finds 47 in four probes (positions 7, 11, 9, 10); the second search, for 30, ends when lolo passes hihi after four probes.

Binary search: halve the range of possible positions

Real run

C source

1#include <stdio.h>
2
3/* a[0..n-1] is sorted in increasing order; returns an index of key, or -1 */
4int binary_search(const int a[], int n, int key) {
5 int lo = 0, hi = n - 1;
6 while (lo <= hi) {
7 int mid = lo + (hi - lo) / 2;
8 if (a[mid] == key) {
9 return mid;
10 }
11 if (a[mid] < key) {
12 lo = mid + 1;
13 } else {
14 hi = mid - 1;
15 }
16 }
17 return -1;
18}

Sorted array a

2
0
5
1
8
2
12
3
16
4
23
5
27
6
31
7
38
8
42
9
47
10
55
11
61
12
70
13
84
14

State

key = 47, lo = 0, hi = 14, probes so far = 0

Blue = the position this step is working on, amber = a position being compared, red = positions just swapped, green = finished or in its final place, a filled blue cell = a value just placed, faded = not part of the structure at this step.

Step 1

A sorted array of 15 keys. First search for 47, then for 30.

1 / 21
The sorted array of 15 keys is set up by hidden driver code, which searches for 47 (present) and then for 30 (absent). binary_search() is the exact code that runs. Faded cells have been ruled out. Produced by: real execution: every array, stack, matrix and list in the picture is read from the running program's memory at each step. Apple clang version 21.0.0 (clang-2100.1.1.101). gcc -O0 -o prog prog.c && ./prog

Why ⌊log⁡2n⌋+1\lfloor \log_2 n \rfloor + 1. After kk probes at most n/2kn/2^k positions remain (rounded down), so the range is empty after at most ⌊log⁡2n⌋+1\lfloor \log_2 n \rfloor + 1 probes. More exactly, a range of size mm becomes a range of size at most ⌊m/2⌋\lfloor m/2 \rfloor, and ⌊m/2⌋=0\lfloor m/2 \rfloor = 0 only after the size has been halved ⌊log⁡2m⌋+1\lfloor \log_2 m \rfloor + 1 times. The recurrence of the running time is T(n)=T(n/2)+1T(n) = T(n/2) + 1, which gives Θ(log⁡n)\Theta(\log n) (Master theorem, case 2).

Binary search is optimal. Any algorithm that searches a sorted array by comparing the key with elements must be able to answer "present at position ii" for each of the nn positions, and it can only do so after it has compared the key with aia_i. So its decision tree has at least nn internal nodes, one per key, and each node has at most two continuing branches (less and greater). A binary tree with nn nodes has a path of at least ⌈log⁡2(n+1)⌉\lceil \log_2 (n + 1) \rceil nodes, so some search needs that many comparisons, which is exactly the worst case of binary search.

Why the loop condition and the updates matter. The updates must be lo = mid + 1 and hi = mid - 1, because amida_{mid} has just been examined and excluded. An update lo = mid can loop forever: with lo=3lo = 3 and hi=4hi = 4 the middle is 33 and nothing changes.

The midpoint. The expression (lo + hi) / 2 adds two valid indices; if their sum exceeds the largest int the addition overflows (undefined behaviour for signed integers in C). The expression lo + (hi - lo) / 2 never leaves the range between lolo and hihi. The program below uses 64-bit arithmetic to show the true numbers without invoking undefined behaviour.

#include <stdio.h>
#include <limits.h>
 
int main(void) {
    long long lo = 1500000000, hi = 1600000000;     /* two valid indices of a huge array */
    printf("INT_MAX          = %d\n", INT_MAX);
    printf("lo + hi          = %lld\n", lo + hi);
    printf("fits in an int   = %s\n", lo + hi <= INT_MAX ? "yes" : "no");
    printf("lo + (hi - lo)/2 = %lld\n", lo + (hi - lo) / 2);
    return 0;
}
INT_MAX          = 2147483647
lo + hi          = 3100000000
fits in an int   = no
lo + (hi - lo)/2 = 1550000000

First occurrence. With duplicates, plain binary search returns some matching position. To find the first one (the lower bound, the first position whose element is not smaller than the key) keep the half-open range [lo,hi)[lo, hi) and never stop early:

/* a[0..n-1] is sorted; returns the first position whose element is not smaller than key (n if there is none) */
int lower_bound(const int a[], int n, int key) {
    int lo = 0, hi = n;
    while (lo < hi) {
        int mid = lo + (hi - lo) / 2;
        if (a[mid] < key) {
            lo = mid + 1;
        } else {
            hi = mid;
        }
    }
    return lo;
}

The result is the first position of the key if it is present, and otherwise the position where the key would have to be inserted to keep the array sorted. For the 15-key array of the animation, lower_bound of 30 is 77, which is where 3131 stands.

What binary search needs. Two things at once. Order: without it, discarding half is wrong. Direct access: finding the middle element must cost O(1)O(1). On a sorted linked list reaching the middle costs n/2n/2 steps, then n/4n/4, and so on, in total Θ(n)\Theta(n): binary search on a linked list is no better than linear search. On a sorted array with many insertions, keeping the order costs Θ(n)\Theta(n) shifts per insertion, which is why other structures (balanced search trees, hash tables) are used for dynamic sets.

Outside the syllabus. If the keys are spread evenly, interpolation search guesses the position from the key's value and takes expected O(log⁡log⁡n)O(\log \log n) probes, but its worst case is Θ(n)\Theta(n).

Worked examples

EX 1Trace a binary search

Easy

Array 2,5,8,12,16,23,27,31,38,42,47,55,61,70,842, 5, 8, 12, 16, 23, 27, 31, 38, 42, 47, 55, 61, 70, 84 (positions 0 to 14), key 4747. Probe position 77 (31): too small, lo=8lo = 8. Probe 8+(14−8)/2=118 + (14 - 8)/2 = 11 (55): too big, hi=10hi = 10. Probe 8+(10−8)/2=98 + (10 - 8)/2 = 9 (42): too small, lo=10lo = 10. Probe 1010 (47): found. Four probes, matching the animation. A linear search would have needed 1111.

EX 2The worst-case count for a given n

Easy

The worst case is ⌊log⁡2n⌋+1\lfloor \log_2 n \rfloor + 1. For n=1000n = 1000: 29=512≤1000<1024=2102^9 = 512 \le 1000 < 1024 = 2^{10}, so 1010. For n=106n = 10^6: 219=524288≤106<2202^{19} = 524288 \le 10^6 < 2^{20}, so 2020. For n=2k−1n = 2^k - 1 the answer is kk (the binary tree of probes is perfectly full); for n=2kn = 2^k it is k+1k + 1, one more. In the table above n=7n = 7 gives 33 and n=8n = 8 gives 44.

EX 3An unsuccessful search and the insertion point

Medium

Search for 3030 in the same array. Probe 77 (31): too big, hi=6hi = 6. Probe 33 (12): too small, lo=4lo = 4. Probe 55 (23): too small, lo=6lo = 6. Probe 66 (27): too small, lo=7lo = 7. Now lo=7>hi=6lo = 7 > hi = 6: stop, absent, after four probes. The final lo=7lo = 7 is the position at which 3030 would be inserted, the same value lower_bound returns.

EX 4Average cost of binary search

Medium

For n=2k−1n = 2^k - 1 the probes form a perfectly full tree with 2d−12^{d-1} nodes at depth dd, so a successful search takes dd probes for 2d−12^{d-1} of the keys. The total over all keys is ∑d=1kd⋅2d−1=(k−1)2k+1\sum_{d=1}^{k} d \cdot 2^{d-1} = (k - 1) 2^k + 1. For n=7n = 7 (k=3k = 3) this is 2⋅8+1=172 \cdot 8 + 1 = 17, which is the bin-hit value in the table, and for n=15n = 15 it is 3⋅16+1=493 \cdot 16 + 1 = 49, also in the table. The average is ≈k−1\approx k - 1: about one probe fewer than the worst case.

EX 5Binary search on a linked list, and on unsorted data

GATE level

(a) A sorted singly linked list of nn nodes is searched with the binary search idea: to examine the middle of a range of mm nodes we walk m/2m/2 steps, so the total work is n/2+n/4+⋯=Θ(n)n/2 + n/4 + \cdots = \Theta(n) steps, although only O(log⁡n)O(\log n) comparisons are made. The time is Θ(n)\Theta(n), not Θ(log⁡n)\Theta(\log n). (b) Binary search on an array that is not sorted is not slower, it is wrong: for 5,1,4,2,35, 1, 4, 2, 3 and the key 22 the first probe (position 2, value 4) says "too big", the left half 5,15, 1 is kept, and the key is missed. (c) A sorted array of nn keys is searched qq times: with binary search the time is Θ(qlog⁡n)\Theta(q \log n); with linear search Θ(qn)\Theta(qn). If qq is small (say q=1q = 1) sorting first, at Θ(nlog⁡n)\Theta(n \log n), costs more than one linear search.

Cheat box

Cheat box

  • Linear search: best 11, worst nn, average successful (n+1)/2(n+1)/2, unsuccessful nn. Works on any collection, array or list.
  • Binary search: sorted array with direct access. Invariant: if the key is present it is in [lo,hi][lo, hi]. Worst case ⌊log⁡2n⌋+1=⌈log⁡2(n+1)⌉\lfloor \log_2 n \rfloor + 1 = \lceil \log_2 (n+1) \rceil probes; best case 11; time Θ(log⁡n)\Theta(\log n); T(n)=T(n/2)+1T(n) = T(n/2) + 1.
  • n=2k−1n = 2^k - 1: worst case kk. n=2kn = 2^k: worst case k+1k + 1.
  • Updates are lo = mid + 1 and hi = mid - 1. Midpoint: lo + (hi - lo) / 2.
  • Binary search is optimal among comparison-based searches of a sorted array.
  • On a linked list the comparisons are O(log⁡n)O(\log n) but the time is Θ(n)\Theta(n).
  • Iterative binary search uses O(1)O(1) space; the recursive version uses O(log⁡n)O(\log n) stack.

Traps and GATE patterns

Connections

Binary search is the simplest divide and conquer algorithm: one subproblem of half the size and constant work, see divide and conquer; its recurrence is solved in solving recurrences. A binary search tree makes the same decisions with pointers instead of indices (binary search trees), and a hash table trades order for expected constant time.

PYQs

7 previous year questions from your book. I re-solved each one myself (5 by running or simulating, 2 by reasoning only); the book's key is shown next to my answer. All PYQs

GATE 2021 · Set 1 · MCQ · 1 markQ3 · page 108 of the book
Consider the following array:
23 , 32 , 45 , 69 , 72 , 73 , 89 , 97
Which algorithm out of the following options uses
the least number of comparisons (among the array
elements) to sort the above array in ascending
order?
  • (a)Quicksort using the last element as pivot
  • (b)Selection sort
  • (c)Merge sort
  • (d)Insertion sort
GATE 2024 · Set 1 · MCQ · 1 markQ3 · page 144 of the book
Given an integer array of size N, we want to check
if the array is sorted (in either ascending or
descending order). An algorithm solves this
problem by making a single pass through the array
and comparing each element of the array only with
its adjacent elements. The worst-case time
complexity of this algorithm is
  • (a)Both O(n)and Ω (n)
  • (b)O(n) but not Ω (n)
  • (c)Ω (n) but not O(n)
  • (d)Neither O(n) nor Ω (n) v Check Out Our Gate Courses & Secure Your Dream Rank !
GATE 2021 · Set 2 · MCQ · 1 markQ4 · page 144 of the book
What is the worst-case number of arithmetic
operations performed by recursive binary search
on a sorted array of size n
  • (a)O(n)
  • (b)O(n2)
  • (c)O(√n )
  • (d)O(log2n)]
GATE 2017 · Set 1 · NAT · 2 marksQ5 · page 144 of the book
Let A be an array of 31 numbers consisting of
sequence of 0's followed by a sequence of 1's. The
problem is to find the smallest index i that A[i] is 1
by probing the minimum numbers of locations in A.
The worst case number of probes performed by an
optimal algorithm is   .
GATE 2017 · Set 2 · MCQ · 2 marksQ5 · page 146 of the book
Match the algorithms with their time complexities:
Algorithm
Time
complexity
P Towers of Hanoi with
n disks
i
Θ(n2 )
Q Binary search given n
sorted numbers
ii
Θ(nlog n)
R Heap sort given n
numbers at the worst
case
iii
Θ(2n )
S
Addition of two n × n
matrices
iv
Θ(logn)
ALGORITHMS

Check Out Our Gate Courses & Secure Your Dream Rank !
  • (a)P-(iii), Q-(iv), R-(i), S-(ii)
  • (b)P-(iv), Q-(iii), R-(i), S-(ii)
  • (c)P-(iii), Q-(iv), R-(ii), S-(i)
  • (d)P-(iv), Q-(iii), R-(ii), S-(i)
year not read yetQ10 · page 57 of the book
An unordered list contains n distinct elements. The
number of comparisons to find an element in this list
that is neither maximum nor minimum is :
  • (a)O(nlogn)
  • (b)O(n)
  • (c)O(logn)
  • (d)O(1)
GATE 2014 · Set 3Q29 · page 70 of the book
Consider the C function given below. Assume that
the array listA contains n(>0) elements, sorted in
ascending order
int ProcessArray(int *listA, int x, int n)
{
int i, j, k;
i = 0;
j = n-1;
do {
k = (i+j)/2;
if (x <= listA[k]) j = k-1;
if (listA[k] <= x) i = k+1;
}
while (i <= j);
if (listA[k] == x) return(k);
else return -1;
}
Which one of the following statements about the
function ProcessArray is CORRECT?
  • (a)It will run into an infinite loop when x is not in listA.
  • (b)It is an implementation of binary search.
  • (c)It will always find the maximum element in listA.
  • (d)It will return -11 even when xx is present in listA.

Self-check

Question 1

How many array elements does binary search examine, at most, in a sorted array of 10001000 elements?

Show answer

⌊log⁡21000⌋+1=9+1=10\lfloor \log_2 1000 \rfloor + 1 = 9 + 1 = 10.

Question 2

What is the average number of comparisons of a successful linear search in an array of nn elements if every position is equally likely?

Show answer

(n+1)/2(n + 1)/2.

Question 3

Why does binary search on a sorted linked list not run in O(log⁡n)O(\log n) time?

Show answer

Reaching the middle node takes a number of steps proportional to the length of the range, so the steps add up to n/2+n/4+⋯=Θ(n)n/2 + n/4 + \cdots = \Theta(n). Only the number of comparisons is O(log⁡n)O(\log n).

Question 4

An array of 1515 sorted keys is searched for a key smaller than all of them. How many probes are needed?

Show answer

Four: the probes go to positions 7,3,1,07, 3, 1, 0, and then the range is empty. (15=24−115 = 2^4 - 1, so every search needs at most 44.)

Revision card

One-screen revision

  • Linear search: 11 / (n+1)/2(n+1)/2 / nn probes (best / average successful / worst). Any collection.
  • Binary search: sorted array, direct access, invariant "key in [lo,hi][lo, hi]", worst case ⌊log⁡2n⌋+1\lfloor \log_2 n \rfloor + 1 probes, Θ(log⁡n)\Theta(\log n), T(n)=T(n/2)+1T(n) = T(n/2) + 1, optimal.
  • lo = mid + 1, hi = mid - 1, mid = lo + (hi - lo) / 2.
  • Linked list: comparisons O(log⁡n)O(\log n) but time Θ(n)\Theta(n). Unsorted: wrong.
  • Lower bound variant returns the first position not smaller than the key.

References

  • ·Cormen, Leiserson, Rivest, Stein, Introduction to Algorithms (3rd edition), Chapter 2 Getting Started (2.1 and 2.3, the exercises on linear and binary search)
  • ·Sedgewick and Wayne, Algorithms (4th edition), Section 1.1 (binary search)
  • ·Knuth, The Art of Computer Programming, Volume 3, Section 6.2.1 Searching an ordered table

Verification

The C program on this page was compiled and run; its totals were recomputed by an independent Python implementation, and for every n up to 300 the worst case of binary search was confirmed to be floor(log2 n) + 1 probes for both present and absent keys, with the totals (k - 1) 2^k + 1 for n = 2^k - 1. The first-occurrence variant was compared with bisect_left on 3000 random arrays with duplicates. The animation is a real run of the C code shown (scripts/gen-algo-panel-traces.ts). Textbook chapter references are from memory. The remark on interpolation search is outside the GATE syllabus and is stated from general knowledge. SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand or by a small script (loop counts, recurrences, merge and quicksort counts and averages, hash probes and load-factor formulas, DP tables, MST and shortest-path runs, Floyd matrices); long C programs were not re-read line by line (they are compiled and compared by npm run verify:c, and their printed outputs were checked against the prose); tables and animations are machine output and were read, not re-run; No other defect found. Status raised to self-checked; verified needs a textbook or human check.

last verified: never