Menu
Coddy logo textTech

Бинарный поиск

Последнее обновление

Бинарный поиск находит целевое значение в **отсортированном** массиве, многократно деля окно поиска пополам. Он сравнивает средний элемент с целью: совпадение завершает поиск; иначе половина, которая не может содержать цель, отбрасывается, и окно сужается до другой половины. Каждое сравнение исключает половину оставшихся элементов — поэтому алгоритм работает за O(log n): поиск среди миллиона отсортированных значений требует не более примерно 20 сравнений.

Анимация выше показывает указатели lo, mid и hi и затемняет исключённую половину после каждого сравнения. Единственное непреложное условие: массив уже должен быть отсортирован — для неотсортированных данных нужен линейный поиск или сначала сортировка (см. сортировку слиянием). Та же идея деления пополам лежит в основе двоичного дерева поиска.

Временная и пространственная сложность

СлучайСложностьПримечания
Лучший случайO(1)Средний элемент оказывается целью при первом же сравнении.
Средний случайO(log n)Каждое сравнение делит оставшееся окно пополам.
Худший случайO(log n)Окно сужается до одного элемента, прежде чем найти цель или убедиться в её отсутствии.
ПамятьO(1)Итеративная версия хранит только индексы lo, hi и mid.

Шаг за шагом

ШагЧто происходит
1Установите lo на первый индекс, а hi — на последний индекс отсортированного массива.
2Вычислите средний индекс: mid = (lo + hi) // 2.
3Если a[mid] равен цели, верните mid — найдено.
4Если a[mid] **меньше** цели, цель может быть только в правой половине: установите lo = mid + 1.
5Если a[mid] **больше** цели, ищите в левой половине: установите hi = mid - 1.
6Повторяйте с шага 2, пока lo <= hi; если окно опустело, цели в массиве нет.

Разобранный пример

Поиск 5 в [1, 2, 3, 5, 7, 8, 9]:

ПроходОкно (lo..hi)mida[mid]Действие
1[1, 2, 3, 5, 7, 8, 9] (0..6)35a[3] = 5 — цель найдена по индексу 3.

Промах, шаг за шагом

Поиск 4 в том же массиве показывает, как окно пустеет:

ПроходОкно (lo..hi)mida[mid]Действие
10..6355 > 4 — ищем в левой половине, hi = 2.
20..2122 < 4 — ищем в правой половине, lo = 2.
32..2233 < 4lo становится 3, окно пустеет: не найдено.

Когда использовать бинарный поиск

Используйте, когдаИзбегайте, когда
Данные уже отсортированы (или вы ищете в них много раз)Данные не отсортированы и ищутся лишь один раз — предварительная сортировка стоит O(n log n)
Коллекция поддерживает быстрый произвольный доступ (массивы)У вас есть только последовательный доступ (связные списки)
Набор данных большой — O(log n) особенно хорош в масштабеНабор данных крошечный — простой перебор так же быстр и проще

Чистая, готовая к запуску реализация Binary Search на Python, JavaScript, Java, C++, C, Pseudocode. Выберите язык, скопируйте код или откройте его уже загруженным в плейграунде Coddy.

Код Binary Search на Python

Python
1def binary_search(a, target):2    lo, hi = 0, len(a) - 13    while lo <= hi:4        mid = (lo + hi) // 25        if a[mid] == target:6            return mid7        if a[mid] < target:8            lo = mid + 1  # search the right half9        else:10            hi = mid - 1  # search the left half11    return -112
13
14nums = [1, 2, 3, 5, 7, 8, 9]  # must be sorted15print("Index of 5:", binary_search(nums, 5))16print("Index of 4:", binary_search(nums, 4))
Запустите этот код в плейграунде Python

Вопросы и ответы о бинарном поиске

Какова временная сложность бинарного поиска?
O(log n) в среднем и худшем случаях, потому что каждое сравнение делит оставшееся окно поиска пополам, и O(1) в лучшем случае, когда первый же средний элемент оказывается целью. Итеративная версия использует O(1) дополнительной памяти.
Почему бинарному поиску нужен отсортированный массив?
Шаг деления пополам опирается на порядок: сравнение цели со средним элементом говорит, какую половину отбросить, только если всё слева от середины меньше, а всё справа — больше. Для неотсортированных данных этот вывод неверен — используйте линейный поиск или сначала отсортируйте.
В чём разница между бинарным и линейным поиском?
Линейный поиск просматривает элементы по одному (O(n)) и работает с любым массивом; бинарный поиск делит пополам окно поиска в отсортированном массиве (O(log n)), но требует отсортированного входа. Для горстки элементов разница ничтожна — в масштабе бинарный поиск выигрывает с большим отрывом.
Сколько сравнений нужно бинарному поиску?
Не более примерно log2(n) + 1: 10 сравнений покрывают 1 000 элементов, 20 сравнений — 1 000 000. Именно этот логарифмический рост делает его поиском по умолчанию для отсортированных данных.
В чём классическая ошибка переполнения в бинарном поиске?
Вычисление середины как (lo + hi) / 2 может переполнить целые числа фиксированного размера, когда lo + hi превышает максимум типа. Безопасная форма — mid = lo + (hi - lo) / 2. В Python это не имеет значения (целые числа произвольной точности), но в Java/C/C++ это реальная и знаменитая ошибка.
Бинарный поиск — это то же самое, что двоичное дерево поиска?
Их объединяет идея деления пополам, но структура различается: бинарный поиск — это алгоритм на отсортированном массиве, а двоичное дерево поиска — связная структура данных, которая хранит ключи упорядоченными, так что поиск на каждом узле спускается влево или вправо.
Coddy programming languages illustration

Освойте алгоритмы с Coddy

НАЧАТЬ