Galloping Search
Expand the search range exponentially from a starting position, then apply binary search.
Galloping Search
Galloping search extends exponential search by starting from a known position instead of the beginning of the array. It is designed for scenarios where you already have a nearby index and want to locate a target relative to that position.
This technique appears in merge algorithms such as Timsort, where one run advances quickly into another.
Problem
Given a sorted array $A$, a starting index $s$, and a target $x$, find an index $i$ such that
$$ A[i] = x $$
If no such index exists, return $-1$.
Key Idea
Instead of scanning linearly from $s$, expand outward exponentially:
- Check positions $s + 1, s + 2, s + 4, s + 8, \dots$
- Stop when the value exceeds the target or bounds are reached
This identifies a bounded interval. Then apply binary search within that interval.
Algorithm
galloping_search(A, x, s):
n = length(A)
if A[s] == x:
return s
# forward gallop
i = 1
while s + i < n and A[s + i] <= x:
i = i * 2
l = s + i // 2
r = min(s + i, n - 1)
return binary_search(A, x, l, r)
Binary search:
binary_search(A, x, l, r):
while l <= r:
m = l + (r - l) // 2
if A[m] == x:
return m
elif A[m] < x:
l = m + 1
else:
r = m - 1
return -1
Example
Let
$$ A = [1, 3, 5, 7, 9, 11, 13, 15] $$
Start at
$$ s = 2 \quad (A[s] = 5) $$
Search for
$$ x = 11 $$
Galloping phase:
| step | offset | index | value |
|---|---|---|---|
| 1 | 1 | 3 | 7 |
| 2 | 2 | 4 | 9 |
| 3 | 4 | 6 | 13 |
Now search in range $[4, 6]$. Binary search finds index $5$.
Correctness
The exponential phase guarantees:
- The target lies within the interval $[s + 2^{k-1}, s + 2^k]$ if it exists
- The interval contains all possible positions of $x$ beyond $s$
Binary search then finds the exact index inside this interval.
Complexity
Let $d$ be the distance from $s$ to the target.
| phase | cost |
|---|---|
| galloping | $O(\log d)$ |
| binary search | $O(\log d)$ |
| total | $O(\log d)$ |
Worst case:
$$ O(\log n) $$
Space:
$$ O(1) $$
Variants
- Backward galloping: search left from $s$
- Bidirectional galloping: expand both directions
- Used in merging sorted runs
Use Cases
- Merging two sorted arrays efficiently
- Searching near a known position
- Adaptive algorithms like Timsort
- Sparse or clustered data
Implementation
def galloping_search(a, x, s):
n = len(a)
if a[s] == x:
return s
i = 1
while s + i < n and a[s + i] <= x:
i *= 2
l = s + i // 2
r = min(s + i, n - 1)
while l <= r:
m = l + (r - l) // 2
if a[m] == x:
return m
elif a[m] < x:
l = m + 1
else:
r = m - 1
return -1
func GallopingSearch(a []int, x int, s int) int {
n := len(a)
if a[s] == x {
return s
}
i := 1
for s+i < n && a[s+i] <= x {
i *= 2
}
l := s + i/2
r := s + i
if r >= n {
r = n - 1
}
for l <= r {
m := l + (r-l)/2
if a[m] == x {
return m
} else if a[m] < x {
l = m + 1
} else {
r = m - 1
}
}
return -1
}