Cairn
algorithms · searching · O(log log n) average (uniform data), O(n) worst case

back to Searching

Interpolation Search

Binary search always checks the middle of the remaining range, no matter what the values look like. Interpolation search makes a smarter guess: if the range holds sorted numbers spread out roughly evenly, a target near the top of the value range is probably near the top of the index range too. Instead of always probing the midpoint, it probes wherever straight-line interpolation between arr[lo] and arr[hi] predicts the target should sit — the same idea as flipping straight to "S" in a phone book to look up "Smith" instead of opening to the middle first. On uniformly spread data this converges shockingly fast, in O(log log n) average probes. The catch — the whole reason this page exists — is that the guess is only as good as the uniform-spread assumption, and data that violates it can make interpolation search degrade to a full O(n) linear scan while binary search, indifferent to the values themselves, keeps its O(log n) guarantee regardless.

Try it

Enter a sorted, comma-separated list of numbers and a target, then step through the search. The array will be sorted automatically if it isn't already. The distribution preset loads two contrasting examples — evenly-spread values where interpolation search wins big, and a deliberately skewed array where it degrades toward a linear scan on the exact same data a binary search would still crack in a handful of probes.

Press Load, then Step through the search.

Why it works

Binary search's invariant is "the target, if present, is between lo and hi" — it says nothing about values, so the only unbiased place to look is the middle. Interpolation search keeps that same invariant but adds one more piece of information it's willing to trust: the values at the two ends, arr[lo] and arr[hi], plus the assumption that the values in between are roughly evenly spread across that range. Under that assumption, the fraction of the way the target sits between arr[lo] and arr[hi] by value should be close to the fraction of the way it sits between lo and hi by index — so probe there instead of the midpoint:

pos = lo + floor( (target - arr[lo]) * (hi - lo) / (arr[hi] - arr[lo]) )

Each probe still throws away one side entirely, exactly like binary search — the difference is only where it chooses to look. When the data really is close to uniform, this guess lands close to the answer almost immediately (the classic result is that the expected number of probes is O(log log n), doubly logarithmic — for a billion uniformly-spread elements, binary search needs about 30 probes and interpolation search needs about 5). When it isn't uniform, the guess can be badly wrong, and the range only shrinks by however far off the guess was — in the worst case, by one element per probe, same as a linear scan.

Reference implementation

function interpolationSearch(arr, target) {
  let lo = 0, hi = arr.length - 1;
  while (lo <= hi) {
    if (target < arr[lo] || target > arr[hi]) return -1; // out of range
    if (lo === hi || arr[hi] === arr[lo]) {
      return arr[lo] === target ? lo : -1; // single value left, or a flat run
    }
    const pos = lo + Math.floor((target - arr[lo]) * (hi - lo) / (arr[hi] - arr[lo]));
    if (arr[pos] === target) return pos;
    if (arr[pos] < target) lo = pos + 1;
    else hi = pos - 1;
  }
  return -1; // not found
}

Pitfalls

The uniform-spread assumption can fail badly, and nothing detects it. Load the skewed preset above: eleven consecutive integers 0..10 followed by one outlier a million higher, searching for 10. arr[lo] and arr[hi] are a million apart, so the formula's very first guess lands almost at the far end — and every probe after that only rules out one more index, because the rest of the range is still just as lopsided. This exact array and target take interpolation search 11 probes (effectively a full linear scan of the 12-element array) where binary search, run on the identical array and target, needs only 3. Interpolation search never notices anything went wrong; it just quietly does more work. Real-world data with this shape isn't exotic — timestamps with a burst of activity, IDs with a few far-future placeholders, measurements with an outlier — and there's no cheap way to tell in advance whether a given array is uniform enough to trust, short of already knowing its distribution.

Division by zero, guarded explicitly. If arr[hi] === arr[lo] (every value left in range is the same, a flat run of duplicates) the formula's denominator is zero. The reference implementation above checks for this before computing pos and falls back to a direct comparison — skip that check and a flat run of duplicates anywhere in the array produces NaN instead of an index, silently breaking the search rather than just running slower.

The formula assumes numeric, evenly-comparable values. Binary search only ever needs </>/= and works on any ordered type — strings, dates, custom comparators. Interpolation search's formula does arithmetic on the values themselves, so it only works directly on numbers (or something mapped to numbers first); there's no such thing as interpolating "how far between two strings" without inventing your own numeric encoding first.

Complexity

Average case O(log log n) probes on uniformly-distributed sorted data; worst case O(n) on adversarial or heavily-skewed data, same as a linear scan — the skewed example above is a small, concrete instance of that worst case, not a hypothetical one. Binary search is the safer default precisely because its O(log n) guarantee doesn't depend on the data's shape at all; interpolation search is worth reaching for only when the data is known (not just hoped) to be roughly uniform and the array is large enough for the doubly-logarithmic win to matter — the gap between log log n and log n is negligible for small n and only becomes dramatic at the sizes where every probe is expensive (e.g. a disk seek or a network round trip). See Choosing a Search Algorithm for how it stacks up against the site's other ten Searching entries.