Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лк08_Алгоритмы поиска.doc
Скачиваний:
30
Добавлен:
07.07.2019
Размер:
64 Кб
Скачать

Бинарный (двоичный) поиск

Гораздо больший интерес представляют методы, не только работающие быстро, но и дающие лучшую теоретическую сложность. Один из таких методов – дихотомический поиск.

Этот метод поиска предполагает, что множество хранится, как некоторая отсортированная (например, по возрастанию) последовательность элементов, к которым можно получить прямой доступ посредством индекса. Фактически речь идет о том, что множество хранится в массиве и этот массив отсортирован.

Суть метода заключается в следующем. Сначала К сравнивается со средним ключом в таблице, результат сравнения позволяет определить в какой половине таблицы следует продолжить поиск, применяя к ней ту же процедуру и т.д.

Рассмотрим этот метод более подробно. Областью поиска (l, r) назовем часть массива с индексами от l до r, в которой предположительно находится искомый элемент.

Сначала областью поиска будет часть массива (l, r), где l=1, а r=n, то есть вся заполненная элементами множества часть массива.

Теперь найдем индекс среднего элемента m=(l+r) div 2.

Если Key>A[m], то можно утверждать (поскольку массив отсортирован), что если Key есть в массиве, то он находится в одном из элементов с индексами от m+l до r, следовательно, можно присвоить l=m+1, сократив область поиска.

В противном случае можно положить r=m. На этом заканчивается первый шаг метода. Остальные шаги аналогичны.

На каждом шаге метода область поиска будет сокращаться вдвое. Как только l станет равно r, то есть область поиска сократится до одного элемента, можно будет проверить этот элемент на равенство искомому и сделать вывод о результате поиска.

Бинарный поиск является методом непоследовательного поиска и известен также как метод половинного деления или дихотомии.

Функция Locate возвращает номер искомого ключа или N+1, если ключ не найден.

Function Locate( x:vector; k: integer): integer;

var l, r, i : integer;

begin

l:=1; r:=N;

repeat

i:=(L+r) div 2;

if K>x[i] then l:=i+1

else if K<x[i] then r:=i-1

until (K=x[i]) or (l>r);

if K=x[i] then Locate := i else Locate:=N+1

end;

Бинарный поиск, никогда не использует более чем log2N+1 сравнений как для успешного, так и для неуспешного поиска. А это означает сложность T(log(n)).

Это свойство следует из того, что количество обрабатываемых записей в каждом цикле сокращается вдвое. Количество производимых при этом сравнений равно CN= CN/2+1 при C1= 1, что доказывает данное свойство.

Добавление граничного элемента дает усовершенствованный вариант алгоритма:

Function Locate( x:vector; k: integer): integer;

var l, r, i : integer;

Begin

l:=1; r:=N; x[N+1]:=K;

repeat

i:=(L+r) div 2;

if K>x[i] then l:=i+1

else if K<x[i] then r:=i-1

until K=x[i];

Locate:=i

end;

Интерполяционный поиск

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

Пусть имеется область поиска (l, r). Предположим, что элементы множества – целые числа, возрастающие в арифметической прогрессии. Тогда искомый элемент должен находиться в массиве (если он вообще там есть) под индексом:

.

Это следует из свойств арифметической прогрессии. В этом элементе и будем брать пробу.

l := 1; r := n;

while (l<>r) do

begin

m := l+(r-l)*(Key-A[l])/(A[r]-A[l]);

if Key>A[m] then l := m+1 else r := m;

end;

if A[l]=Key then <элемент найден> else <элемент не найден>;

Мы сделали очень большое допущение, предположив, что элементы массива представляют собой возрастающую арифметическую прогрессию. В реальности такая ситуация встречается редко. Но этот метод хорошо работает для любых пусть не идеально, но более-менее равномерно распределенных данных.

Если же мы имеем дело с неравномерно распределенными данными, то интерполяционный поиск может увеличить число шагов по сравнению с дихотомическим поиском.

Теоретическая сложность интерполяционного поиска – T(log(log(n))). Это, конечно, лучше, чем сложность дихотомического поиска, но эти преимущества становятся достаточно заметными лишь при очень больших значениях n. Практически на всех реальных n разница между дихотомическим и интерполяционным поиском по скорости не существенна.

Контрольные вопросы

  1. Почему последний из разобранных методов поиска называется интерполяционным?

  2. Почему при хранении в списке невозможно воспользоваться дихотомическим и интерполяционным поиском?