Saltar a contenido

1. Linear Search

Linear search — also called sequential search — is the simplest algorithm for locating a target element in a collection: it inspects each element in turn until a match is found or all elements are exhausted. No preconditions are imposed on the collection; it need not be sorted, contiguous in memory, or even finite in advance. Knuth 1 treats it as the baseline against which every faster search method must justify its additional requirements.

Despite its \(O(n)\) worst-case cost, linear search is often the correct choice in practice: for small or unsorted arrays, for linked lists (which do not support \(O(1)\) random access needed by binary search), and as the inner loop of algorithms that search very short sublists.

1.1 Problem Statement

Given a sequence \(A = \langle a_0, a_1, \ldots, a_{n-1} \rangle\) of \(n\) elements drawn from a totally ordered set, and a target value \(t\), find the smallest index \(i\) such that \(a_i = t\), or report that no such index exists.

\[ \begin{equation} \text{result}(A, t) = \begin{cases} \min\{i \in [0, n) : a_i = t\} & \text{if } t \in A \\ \bot & \text{otherwise} \end{cases} \label{eq:linear_search_result} \end{equation} \]
Variables
Symbol Meaning
\(A\) The input sequence of length \(n\)
\(n\) Number of elements in \(A\)
\(a_i\) Element at index \(i\)
\(t\) Target value to search for
\(\bot\) Sentinel indicating absence

1.2 The Algorithm

The procedure is direct: maintain a cursor \(i\) starting at 0, compare \(a_i\) with \(t\), advance if they differ, and halt when they match or the array ends.

LINEARSEARCH(A, n, t):
  for i = 0 to n - 1:
    if A[i] = t:
      return i
  return ⊥

1.2.1 Loop Invariant

At the start of each iteration with cursor value \(i\):

\(t \notin \{a_0, a_1, \ldots, a_{i-1}\}\)

That is, the target has not been found in any position before \(i\). On termination either the invariant is broken by a match at position \(i\) (return \(i\)), or \(i\) reaches \(n\) with the invariant still holding, confirming absence (return \(\bot\)).

1.3 Complexity Analysis

1.3.1 Comparisons

Let \(C(n)\) denote the number of element–target comparisons.

Best case (\(t = a_0\)): the first comparison succeeds.

\[C_{\min} = 1\]

Worst case (\(t \notin A\) or \(t = a_{n-1}\)): every element is inspected.

\[C_{\max} = n\]

Average case (uniform distribution over positions, \(t\) present with probability \(p\)):

The expected number of comparisons when \(t\) is at position \(j\) (uniformly distributed over \(\{0, \ldots, n-1\}\)) is:

\[ \begin{equation} C_{\text{avg}} = p \cdot \frac{n+1}{2} + (1-p) \cdot n \label{eq:linear_avg} \end{equation} \]

When \(t\) is always present (\(p = 1\)): \(C_{\text{avg}} = (n+1)/2\). When \(t\) is never present (\(p = 0\)): \(C_{\text{avg}} = n\).

1.3.2 Summary

Case Comparisons Space
Best \(O(1)\) \(O(1)\)
Average \(O(n)\) \(O(1)\)
Worst \(O(n)\) \(O(1)\)

Linear search is in-place (\(O(1)\) extra space) and does not require preprocessing.

1.4 Optimality

For an unsorted collection with no additional data structure, linear search is information-theoretically optimal: every element must be a candidate until proven otherwise, so any algorithm must in the worst case inspect all \(n\) elements. This follows from an adversary argument: for any deterministic algorithm that halts before inspecting all elements, the adversary can place \(t\) in the last unexamined position.

For a sorted collection, binary search achieves \(O(\log n)\) and is strictly superior for large \(n\) (see Binary Search).

1.5 Variants

A sentinel is a copy of \(t\) placed at position \(A[n]\) (a temporary extension of the array) before the scan. This eliminates the bounds check i < n from every iteration, replacing two comparisons per step with one:

SENTINELSEARCH(A, n, t):
  A[n] = t          // write sentinel
  i = 0
  while A[i] ≠ t:
    i = i + 1
  if i < n:
    return i
  return ⊥

The sentinel guarantees the loop terminates without an explicit bounds check. The savings are constant-factor only but matter in tight inner loops on large arrays.

1.5.2 Self-Organising Search (Move-to-Front)

If elements are searched repeatedly with non-uniform probabilities, moving each found element to the front of the list after each access reduces the expected search length over time. Under the independent reference model, the move-to-front heuristic achieves expected search length that is at most twice optimal for any fixed probability distribution 1.

A weaker variant: swap the found element with its predecessor rather than moving it to the front. This adapts more slowly but causes less disruption for distributions where one element does not dominate all searches.

When \(A\) is sorted, comparing \(a_i > t\) (rather than just \(a_i \neq t\)) allows early termination on failure: once an element exceeding \(t\) is encountered, all subsequent elements also exceed \(t\), so \(t\) cannot be present. This reduces the average unsuccessful search cost from \(n\) comparisons to \(\approx n/2\).

Property Linear search Binary search
Precondition None Sorted array
Data structure Any iterable Random-access array
Worst-case cost \(O(n)\) \(O(\log n)\)
Best-case cost \(O(1)\) \(O(1)\)
Preprocessing None Sorting: \(O(n \log n)\)
Space \(O(1)\) \(O(1)\)

The crossover point — where the preprocessing cost of sorting amortises over many binary searches — is \(k \approx n \log_2 n / \log_2 n = n\) searches (ignoring constants). For fewer than \(n\) total searches on an unsorted array, linear search is cheaper overall.

1.7 Applications

  • Small arrays (\(n \lesssim 8\)): the constant overhead of binary search (index arithmetic, bounds checks) makes linear search faster in practice.
  • Linked structures: traversal is inherently sequential, so \(O(1)\) random access required by binary search is unavailable.
  • Streaming data: elements arrive one at a time with no prior knowledge of the sorted order; search must be done as data is ingested.
  • Last-element searching: variants such as find_last_of in C++ or rfind scan right to left.
  • Inner loop of algorithms: e.g. insertion sort's inner scan to find the insertion position, or linear-time bucket search.

1.8 Interactive Demo

The animation below shows linear search on a 16-element array. Click Present to search for a target that exists, or Absent to search for one that does not (triggering a full scan).


  1. Donald E. Knuth. The Art of Computer Programming, Vol. 3: Sorting and Searching. Addison-Wesley, 2nd edition, 1998. ISBN 978-0-201-89685-5. ↩↩