Двоичный (бинарный) поиск, BinSearch, БинПоиск

Поиск в упорядоченном массиве за $O(\log{n})$. Так же его называют - метод деления пополам и дихотомия (деление пополам по-гречески).

Перед применением двоичного поиска нужно отсортировать массив одним из алгоритмов сортировки.

Цель

Найти элемент со значением $x$ в отсортированном массиве $A$ из $N$ элементов или установить, что элемента $x$ в массиве $A$ нет.

Идея

Разделить отсортированный массив на две половины, сравнить средний элемент с $x$, понять в какой половине массива может находиться значение $x$ и перейти к поиску в этой половине.. И так далее, пока размер массива не уменьшиться до 1 элемента, тогда либо этот элемент равен $x$ и мы нашли $x$, либо не равен $x$, и тогда элемента $x$ нет в массиве $A$.

Скорость работы

Линейный поиск (последовательный просмотр всех элементов массива) выполняется за $O(N)$ операций, двоичный поиск - за $O(\log{N})$.

Пример реализации на C++

Шаблонная функция и пример её использования:
template <typename  T> int binary_serch (const T *a,int n ,const  T &elem);
Пусть $а$ - отсортированный массив, тогда функция за логарифмическое время возвращает $i$-ый индекс элемента массива elem=a[i] и -1, если элемент не найден.

#include <iostream> // Отсюда будем использовать вывод на экран при потоков (cout)
#include <algorithm> // Алгоритм сортировки (функция sort) из STL
#include <stdlib.h> // Функция rand() - случайные числа
#include <ctime> // Функция time() - время
#include <conio.h> // Функция getch() - ожидание нажатия клавиши в конце программы

// Шаблонная функция
template <typename T> int binary_search(const T *a, int n, const T &elem){
  int L = 0, R = n-1; // Левая и правая границы поиска
  while (L < R){ // Пока в рассматриваемом куске массива больше одного элемента
    int m = (L+R)/2; // Вычисляем индекс среднего элемента
    if (elem <= a[m]) // Если искомый элемент меньше центрального
      R = m; // Сдвигаем правую границу влево
    else // , а иначе
      L = m+1; // Левую границу вправо
  }
  // Остался один элемент с индеком L = R, 
  // и это либо искомый элемент elem, либо elem в массиве вообще нет!
  return (a[R] == elem) ? R : -1; // возвращаем индекс или -1 если элемент не найден 
}

using namespace std; // Чтобы не писать перед каждым cout "std::"

// Основная программа c примером использования
int main() {
  // Создаём случайный массив из N элементов
  const int N = 20;
  int a[N];
  // Заполняем массив a случайными целыми числами 
  srand(time(0)); // Инициализация генератора случайных чисел
  for(int i=0;i<N;i++)
    a[i] = rand() % 200; // случайные числа в диапазоне 0..199
  int el1 = a[rand() % N]; // Запоминаем случайный элемент массива
    // он точно будет в отсортированном массиве :)
  // Сортируем массив a при помощи функции sort из STL
  sort(a, a+N); // Да-да.. вот так просто, одной строкой, можно отсортировать массив ;)
  // Выводим массив на экран 
  for(int i=0;i<N;i++)
    cout << "a[" << i << "] = " << a[i] << endl;
  // Поиск элементов массива при помощи функции binary_search
  // Ищем элемент массива, который там заведомо есть 
  cout << "search " << el1 << " " << binary_search(a,N,el1) << endl;
  // Поиск элемента, которого в массиве a заведомо нет, т.к. он больше 199
  cout << "search " << 1000 << " " << binary_search(a,N,1000) << endl;

  cout << "Press any key..."; getch(); // Ожидаем нажатия клавиши :)
  return 0;
}

Стандартная STL функция binary_search возвращает лишь найден элемент или нет.

#include <iostream> // Вывод на экран
#include <algorithm> // Алгоритм сортировки из STL
#include <stdlib.h> // Функция rand() - случайные числа
#include <ctime> // Функция time() - время

// Основная программа для демонстрации функции 
using namespace std; // Чтобы не писать везде "std::"

int main() {
  // Создаём случайный массив из N элементов
  const int N = 20;
  int a[N];
  // Заполняем случайными числами 
  srand(time(0)); // Инициализация генератора случаных чисел
  for(int i=0;i<N;i++)
    a[i] = rand() % 200;
  int el1 = a[rand() % N]; // Запоминаем элемент массива
  // Сортируем массив a 
  sort(a, a+N);
  // Выводим массив на экран 
  for(int i=0;i<N;i++)
    cout << "a[" << i << "] = " << a[i] << endl;
  // Поиск элементов массива
  // Ищем элемент массива, который там заведомо есть 
  cout << "search " << el1 << " " << binary_search(a,a+N,el1) << endl;
  cout << "search " << 1000 << " " << binary_search(a,a+N,1000) << endl;
  return 0;
}

Реализация на Delphi

Добавить картинки

{$APPTYPE CONSOLE}

uses SysUtils;

procedure swap(var a, b: int64);
var t: int64;
begin
  t := a; a := b; b := t;
end;

var
  n, i, j, m, k, ans, l, r: integer;
  a: array [1..1000000] of int64;

procedure qsort(l, r: integer);
var
  i, j: integer;
  m: int64;
begin
  i := l;
  j := r;
  m := a[random(r - l + 1) + l];
  while i <= j do begin
    while a[i] < m do inc(i);
    while a[j] > m do dec(j);
    if i <= j then begin
      swap(a[i], a[j]);
      inc(i);
      dec(j);
    end;
  end;
  if i < r then qsort(i, r);
  if l < j then qsort(l, j);
end;

begin
  assign(input, 'find.in'); reset(input);
  assign(output, 'find.out'); rewrite(output);

  read(n, l);
  for i := 1 to n do
    read(a[i]);

  qsort(1, n);

  for j := 1 to l do begin
    read(k);
    l := 1;
    r := n + 1;
    While r - l > 1 do begin
      m := (r + l) div 2;
      if k >= a[m] then l := m else r := m;
    end;
    if k = a[l] then writeln('YES') else writeln('NO');
  end;
end.