Expand the search range exponentially from a starting position, then apply binary 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 starting index , and a target , find an index such that
If no such index exists, return .
Key Idea
Instead of scanning linearly from , expand outward exponentially:
- Check positions
- 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 -1Example
Let
Start at
Search for
Galloping phase:
| step | offset | index | value |
|---|---|---|---|
| 1 | 1 | 3 | 7 |
| 2 | 2 | 4 | 9 |
| 3 | 4 | 6 | 13 |
Now search in range . Binary search finds index .
Correctness
The exponential phase guarantees:
- The target lies within the interval if it exists
- The interval contains all possible positions of beyond
Binary search then finds the exact index inside this interval.
Complexity
Let be the distance from to the target.
| phase | cost |
|---|---|
| galloping | |
| binary search | |
| total |
Worst case:
Space:
Variants
- Backward galloping: search left from
- 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 -1func 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
}