Целочисленный двоичный поиск

Материал из Викиконспекты
Перейти к: навигация, поиск
Определение:
Целочисленный двоичный поиск (бин. поиск) - алгоритм поиска аргумента для заданного значения монотонной целочисленной функции.


Формулировка задачи

Пусть нам дана монотонная функция, значения которой целые числа. Нам необходимо найти место, где функция будет равна заданному значению.

Выбор границы

Нам должны быть заданы границы, на которых мы ищем индекс заданного значения х.

Правосторонний/левосторонний целочисленный двоичный поиск

Когда мы ищем правосторонним бин. поиском, то он возвращает индекс самого правого вхождения заданного значения х.
Когда же поиск левосторонний, возвращается индекс самого левого вхождения заданного значения х.
Это разделение помогает находить количество подряд идущих равных значений.
Например:
Задан отсортированный массив [1, 2, 2, 2, 2, 3, 5, 8, 9, 11]
Правосторонний поиск двойки выдаст в результате 5, в то время как левосторонний выдаст 2.
От сюда следует, что количество подряд идущих двоек равно длине отрезка [2;5] = 4.
Если искомого элемента нету, то правосторонний поиск выдаст минимальный элемент, больший искомого, а левосторонний наоборот, максимальный элемент, меньший искомого.

Алгоритм правостороннего/левостороннего поиска

Схема бин. поиска

Идея поиска заключается в том, чтобы брать элемент посередине, между границами, и сравнивать его с искомым. В случае равенства возвращать его, а если искомое больше(в случае правостороннего - не меньше), чем элемент сравнения, то сужаем область поиска так, чтобы новая левая граница была равна индексу середины предыдущей области. В противном случае присваиваем это значение правой границе. Проделываем эту процедуру до тех пор, пока правая граница больше левой более чем на 1, или же пока мы не найдём искомый индекс.

Код

 l = 0; // l - левая граница
 r = n + 1; // r - правая граница
 while (l < r - 1) // запускаем цикл
   m = (l + r) div 2; // m - середина области поиска
   if (a[m] < k)
     l = m; 
   else 
     r = m; // сужение границ
 if (a[r] = k)
   result = r; // выводим найденный индекс
 else 
   result = -1; // если элемент не найден возвращаем -1

В случае правостороннего поиска изменится знак сравнения при сужении границ на (a[m] <= k), также при выводе найденного индекса, мы сравниваем искомый элемент k с a[l].