Предположим, вы ищете человека по имени «Винсент» в одном из этих больших телефонных справочников. Эти книги могут иметь сотни страниц, и было бы утомительно искать каждую страницу с самого начала линейным способом, пока вы не найдете этого человека. К счастью, книга отсортирована по алфавиту, так что мы можем использовать хак.

Представьте, что вы открываете книгу посередине. Вы смотрите на страницу и видите имена, начинающиеся с «S». Зная, что «V» стоит после «S», вы разрываете книгу пополам и выбрасываете половину книги с именами ниже «S». Теперь у вас осталась небольшая книга.

Затем вы снова открываете оставшуюся книгу наполовину. Вы смотрите туда, где вы приземлились, и видите имена, начинающиеся с «Х». Вы снова разрываете книгу пополам и выбрасываете половину с именами выше «X».

Продолжайте повторять эту процедуру, и достаточно скоро вы окажетесь на страницах, начинающихся с «V».

Это концепция бинарного поиска. Двоичный поиск — это эффективный алгоритм поиска значений в отсортированном массиве или списке. Он является частью большой категории алгоритмов под названием разделяй и властвуй. Эти классы алгоритмов берут сложную проблему и делят ее на более мелкие части подзадач, которые легче решить. Для бинарного поиска на каждом этапе решения задача каждый раз в основном уменьшается вдвое.

Чтобы проиллюстрировать процесс этого алгоритма, предположим, что мы хотим найти 89 в следующем упорядоченном массиве чисел. Нижняя и верхняя части диаграммы — это переменные, содержащие соответственно начальный и конечный индексы.

Начнем с вычисления среднего значения с использованием нижней и верхней переменных. Среднее значение равно 47, и это не то значение, которое нам нужно. Поскольку мы знаем, что 47 ‹ 89, мы можем исключить левую половину массива (все значения до 47 включительно). Это делается путем присвоения нижней переменной среднего индекса + 1. Размер нашей задачи уменьшился вдвое.

Процесс повторяется снова. Мы вычисляем среднее значение равным 97. Тогда мы знаем, что 97 > 89 и правую половину массива можно исключить из поиска, установив для верхней переменной средний индекс - 1.

Повторяем процесс снова. Среднее значение равно 89. Мы видим, что 89 = 89, поэтому мы можем остановить поиск и вернуть значение или индекс!

Линейный поиск занял бы у нас 7 шагов, но бинарный поиск занял бы у нас только 3 шага, чтобы найти 89. Для меньших массивов время вычислений между двумя алгоритмами будет незначительным. Однако для больших наборов данных — речь идет о миллионах значений — бинарный поиск более эффективен, чем линейный поиск.

Псевдокод

Шаги бинарного поиска можно записать так:

  1. Создайте переменную с именем «bottom», указывающую на нижнюю границу подмассива.
  2. Создайте переменную с именем «top», указывающую на верхнюю границу подмассива.
  3. Создайте переменную с именем «middle», чтобы указать на середину подмассива.
  4. Пока нижний ‹= верхний, сделайте следующее:
  • Вычислить среднее значение
  • Если среднее значение = целевое значение, вернуть индекс
  • если среднее значение ‹ целевое значение, установить нижнее = среднее + 1
  • Если среднее значение › целевое значение, установите верхнее значение = среднее -1

5. Целевое значение не существует в массиве

Пример реализации на JS

Визуальная демонстрация

Это небольшое приложение наглядно демонстрирует идею бинарного поиска. Целевое значение — это число, которое мы пытаемся угадать, а предположения, которые делает пользователь, — это среднее значение в нашем алгоритме бинарного поиска.



Репозиторий GitHub: