Лабораторная работа
7
ДВОИЧНЫЙ ПОИСК
·
В
программировании бинарный поиск применяется для нахождения элемента Х в
отсортированном массиве. Встречаются другие названия этого метода поиска:
двоичный, логарифмический, метод деления пополам, дихотомия.
·
Основная
идея заключается в следующем.
·
Пусть
массив, состоящий из N элементов, отсортирован в порядке убывания. Находим
средний элемент массива А[m] , где m=(N+1) div 2 . Сравниваем его с элементом
Х. Если средний элемент равен Х, то поиск заканчивается. Если же он меньше Х,
то все элементы с индексами большими или равными m можно не рассматривать. Если
же средний элемент больше Х, то исключаются элементы с индексами, меньшими или
равными m.
·
При
выполнении этого алгоритма на каждом шаге пересчитываются границы поиска. Так
на первом шаге левая граница - L=1, правая - R=N. На втором шаге либо левая,
ибо правая граница поменяют свое значение. Поиск будет продолжатся до тех пор
пока элемент не будет найден, либо пока левая и правая граница поиска не
совпадут, что соответствует отсутствию элемента в массиве.
Алгоритм имеет следующий
вид:
flag = «ложь»;
L=0;
R=N-1;
Начало цикла 1: выполнять пока (L ≤ R) и (flag = =«ложь»);
m=(R+L)/2;
если(a[m]
= = X)
тогда
flag = «истина»;
иначе
если a[m]>X
тогда
R=m+1;
иначе
L=m-1;
все
все
конец цикла 1
Если (flag= = true) то
печать сообщения:
«Элемент Х найден, его номер - m»,
иначе печать:
«Элемента Х нет!»,
ПримеркоданаязыкепрограммированияCидляпоискаэлементаxвмассивеa[n],
отсортированноговвозрастающемпорядке:
size_tfirst=0;/*
Номер первого элемента в массиве */
size_tlast=n;/*
Номер элемента в массиве, СЛЕДУЮЩЕГО ЗА последним */
/*
Если просматриваемый участок непустой, first<last */
size_tmid;
if(n==0)
{
/*
массив пуст */
}
elseif(a[0]>x)
{
/*
не найдено; если вам надо вставить его со сдвигом - то в позицию 0 */
}
elseif(a[n-1]<x)
{
/*
не найдено; если вам надо вставить его со сдвигом - то в позицию n */
}
while(first<last)
{
/*
ВНИМАНИЕ! В отличие от более простого (first+last)/2, этот код стоек к
переполнениям.
Если first и last знаковые, возможен
код (unsigned)(first+last) >> 1.
*/
mid=first+(last-first)/2;
if(x<=a[mid])
{
last=mid;
}
else
{
first=mid+1;
}
}
/*
Если условный оператор if(n==0) и т.д. в начале опущен - значит, тут
раскомментировать! */
if(/*
last<n &&*/a[last]==x)
{
/*
Искомый элемент найден. last - искомый индекс */
}else
{
/*
Искомый элемент не найден. Но если вам вдруг надо его вставить со сдвигом, то
его место - last. */
}
Несмотрянато, чтокоддостаточнопрост,
внёместьнескольколовушек.
УчёныйЙонБентлиутверждает, что90%
студентов, разрабатываядвоичныйпоиск, забываютучестькакое-либоизэтихтребований.
Идажевкод, написанныйсамимЙономиходившийизкнигивкнигу, вкраласьошибка:коднестоеккпереполнениям.
Приложения
Практическиеприложенияметодадвоичногопоискаразнообразны:
·
·
Фрагмент
программы на Паскале имеет следующий вид:
·
·
L:=1;
R:=N; P:=false;
·
WHILE
(L<=R) AND (P=FALSE) DO
·
begin
·
M:=(R+
L) DIV 2;
·
IF
A[M]=X THEN P:=TRUE
·
ELSE
·
IF
A[M]>X THEN L:=M+1
·
ELSE
R:=M-1
·
end;
·
После
выполнения цикла номер элемента, равного Х, хранится в переменной R. Если
R<L, значит совпадений нет.
·
Пусть
К - количество операций сравнения, которые необходимы для нахождения элемента в
упорядоченном массиве методом бинарного поиска. Число К определяется из
следующего неравенства: N<=2 K . Отсюда К можно вычислить по формуле: К=[log
2 N]+1