A fast search method that finds targets in a sorted array by repeatedly cutting the search area in half.
Problem Statement
Suppose we have a sorted array a1≤a2≤…≤an and we want to find the position of a value , i.e. such an index that . If does not exist in the array, we should return .
x
i
ai=x
x
−1
Example: a=[2,5,8,12,16,23] and x=12, Then the answer is position 4.
Brute force solution
The first idea is to go from left to right and compare every element with x.
This works because if x exists, we will eventually find it. If the loop finishes, then there is no such value.
The problem is speed. One search takes O(n) time. For a large array and many queries, this is too much.
Efficient solution and algorithm
Binary search: finding x
C++
source · C++line 1
1int binary_search_any(int x) {
2 int l = 1;
3 int r = n;
4 while (l < r) {
5 int m = (l + r) / 2;
6 if (a[m] < x) {
7 l = m + 1;
8 } else {
9 r = m;
10 }
11 }
12 if (a[l] == x) {
13 return l;
14 }
15 return -1;
16}
Start
L1
We search for the index where a[i] = 16.
inv
If x exists, its index is inside the current [l, r].
a7 cells
whole array
-
2
5
8
12
16
23
0
1
2
3
4
5
6
n6x16l?r?m?state⤳find an index with a[i] == x
iterations0complexityO(log n)
L1
01 / 18
Binary search: x does not exist
C++
source · C++line 1
1int binary_search_any(int x) {
2 int l = 1;
3 int r = n;
4 while (l < r) {
5 int m = (l + r) / 2;
6 if (a[m] < x) {
7 l = m + 1;
8 } else {
9 r = m;
10 }
11 }
12 if (a[l] == x) {
13 return l;
14 }
15 return -1;
16}
Start
L1
We search for the index where a[i] = 10.
inv
If x exists, its index is inside the current [l, r].
a7 cells
whole array
-
2
5
8
12
16
23
0
1
2
3
4
5
6
n6x10l?r?m?state⤳find an index with a[i] == x
iterations0complexityO(log n)
L1
01 / 15
The array is sorted, so we can skip many elements at once. Instead of checking positions one by one, we look at the middle position m.
If am<x, then am is too small. Since the array is sorted, all elements before m are also too small. So we can remove the left part and continue on the right.
If am≥x, then this position is already big enough. Maybe it is equal to x, or maybe the first value at least x is even earlier. So we keep the left part, including m.
This implementation does not directly search “any equal x”. It first finds the first position where ai≥x. After the loop, we check if this position really contains x.
For example, let a=[2,5,8,12,16,23] and x=16. Binary search finds the first position where the value is at least 16. That position has value 16, so we return it.
For: a=[2,5,8,12,16,23] and x=10, binary search finds the first position where the value is at least 10, which is value 12. But 12=10, so the answer is −1.
Before the loop, we must choose the borders correctly. Because our array is 1-indexed, the first possible position is 1 and the last possible position is n. So we write:
The meaning is: if the answer exists, it is somewhere inside the current range [l,r].
Algorithm:
Each step removes about half of the current range, so the search becomes very fast.
Implementation
Complexity
Each query:O(logn) — every step cuts the range.
Total:O(qlogn) — we answer q queries.
Memory:O(n) — we store the array.
1. Start with l = 1 and r = n.
2. While l < r:
1. Let m = (l + r) / 2.
2. If a[m] < x, then elements in positions [l, l + 1, ..., m] are too small. Set l = m + 1.
3. Otherwise, a[m] >= x, so the answer can be at m or before it. Set r = m.
3. Now l = r, so only one candidate remains.
4. If a[l] = x, return l.
5. Otherwise, return -1.
int find_linear(int x){ for(int i = 1; i <= n; i++){ if(a[i] == x){ return i;}} return -1; // if x doesn't exist in array}
int l = 1;int r = n;
#include <bits/stdc++.h>using namespace std;const int N = 200005;int n, q;int a[N];int binary_search_any(int x){ int l = 1; int r = n; while(l < r){ int m =(l + r) / 2; if(a[m]< x){ l = m + 1;} else{ r = m;}} if(a[l] == x){ return l;} return -1;}int main(){ cin >> n >> q; for(int i = 1; i <= n; i++){ cin >> a[i];} while(q--){ int x; cin >> x; cout << binary_search_any(x)<< '\n';} return 0;}