Поиск в отсортированном массиве

Базовый Algorithms
≈ 2 мин чтения

Классический шаблон

Для поиска конкретного значения удобно хранить замкнутый диапазон [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 в шаблоне с замкнутым диапазоном. Если середина не исключается, цикл может перестать уменьшать область поиска.