Поиск в отсортированном массиве
Классический шаблон
Для поиска конкретного значения удобно хранить замкнутый диапазон [left, right].
Пока левая граница не прошла правую, в диапазоне остаются непроверенные кандидаты.
static int binarySearch(int[] values, int target) {
int left = 0;
int right = values.length - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (values[mid] == target) {
return mid;
}
if (values[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return -1;
}
Если середина меньше цели, позиция mid уже точно не подходит, поэтому новая левая граница —
mid + 1. Если середина больше цели, симметрично используется mid - 1.
Зачем так вычислять mid
Формула left + (right - left) / 2 выражает ту же середину, что и
(left + right) / 2, но не требует сначала складывать два потенциально больших индекса.
Это безопасный шаблон, который стоит использовать по привычке.
Если элементов с target несколько
Этот вариант гарантирует, что вернётся какая-то позиция с искомым значением, но не обещает первую или последнюю. Для поиска конкретной границы нужно изменить условие остановки и способ сужения диапазона — этим займёмся дальше.
left = mid или right = mid
в шаблоне с замкнутым диапазоном. Если середина не исключается, цикл может перестать уменьшать область поиска.