Двоичный (бинарный) поиск, 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.