Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекция2.doc
Скачиваний:
4
Добавлен:
10.12.2018
Размер:
214.53 Кб
Скачать

1.2. Поиск делением пополам (двоичный поиск)

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

A k: 1 ≤ k ≤ N: ak-1 ≤ ak (1.39)

Основная идея—выбрать случайно некоторый эле­мент, предположим am, и сравнить его с аргументом поиска х. Если он равен х, то поиск заканчивается, если он меньше х, то мы заключаем, что все элементы с индексами, меньшими или равными m, можно ис­ключить из дальнейшего поиска; если же он больше х, то исключаются индексы больше и равные т. Это соображение приводит нас к следующему алгоритму (он называется «поиском делением пополам»). Здесь две индексные переменные L и R отмечают соответ­ственно левый и правый конец секции массива а, где еще может быть обнаружен требуемый элемент.

L:=1; R:=N; found:=FALSE; (1.40)

WHILE (L<=R) and NOT found DO

BEGIN

m:=(L+R) DIV 2; { выбрираем любой элемент между элементами с номерами L и R }

IF a[ m ]=x THEN found:=TRUE ELSE

IF a[ m ]<x THEN L:=m+1 ELSE R:=m-1;

END;

If found then writeln( ‘искомый элемент ‘,a [ m ] );

Инвариант цикла, т. е. условие, выполняющееся перед каждым шагом, таков:

( L ≤ R ) & ( A k: 1 ≤ k < L : ak < х ) & ( A k: R < k ≤ N : ak > х ) (1.41)

из чего выводится результат

found OR (( L > R ) & ( A k: 1 ≤ k < L : ak < х ) & ( A k: R < k ≤ N : ak > х ))

откуда следует

( am = x ) OR ( A k: 1 ≤ k ≤ N : ak ≠ х ).

Выбор m совершенно произволен в том смысле, что корректность алгоритма от него не зависит. Однако на его эффективность выбор влияет. Ясно, что наша задача — исключить на каждом шагу из дальнейшего поиска, каким бы ни был результат сравнения, как можно больше элементов. Оптимальным решением будет выбор среднего элемента, так как при этом в любом случае будет исключаться половина массива. В результате максимальное число сравнений равно log2(N), округленному до ближайшего целого. Таким образом, приведенный алгоритм существенно выиг­рывает по сравнению с линейным поиском, ведь там ожидаемое число сравнений - N/2.

Эффективность можно несколько улучшить, поме­няв местами заголовки условных операторов. Про­верку на равенство можно выполнять во вторую оче­редь, так как она встречается лишь единожды и при­водит к окончанию работы. Но более существенно следующее соображение: нельзя ли, как и при линей­ном поиске, отыскать такое решение, которое опять бы упростило условие окончания. И мы действитель­но находим такой быстрый алгоритм, как только от­казываемся от наивного желания кончить поиск при фиксации совпадения. На первый взгляд это кажется странным, однако при внимательном рассмотрении обнаруживается, что выигрыш в эффективности на каждом шаге превосходит потери от сравнения с не­сколькими дополнительными элементами. Напомним, что число шагов в худшем случае – log2(N). Быстрый алгоритм основан на следующем инварианте:

( A k: 1 ≤ k < L : ak < х ) & ( A k: R < k ≤ N : ak ≥ х ) (1.42)

причем поиск продолжается до тех пор, пока обе сек­ции не «накроют» массив целиком.

L:=1; R:=N+1;

WHILE L<R DO

BEGIN

j:= (L+R) DIV 2;

IF a [ j ] < x THEN L:=j+1 ELSE R:=j;

END;

IF a [ R ] = x THEN writeln( ‘искомый элемент ‘,a [ R ] );

Условие окончания – L ≥ R, но достижимо ли оно? Для доказательства этого нам необходимо пока­зать, что пр и всех обстоятельствах разность R - L на каждом шаге убывает. В начале каждого шага L < R. Для среднего арифметического m справедливо условие L ≤ m < R. Следовательно, разность дей­ствительно убывает, ведь либо L увеличивается при присваивании ему значения m + 1, либо R уменьша­ется при присваивании значения m. При L = R по­вторение цикла заканчивается. Однако наш инвари­ант и условие L = R еще не свидетельствуют о совпа­дении. Конечно, при R = N+1 никаких совпадений нет. В других же случаях мы должны учитывать, что эле­мент а [ R ] в сравнениях никогда не участвует. Следо­вательно, необходима дополнительная проверка на равенство а [ R ] = х. В отличие от первого нашего ре­шения (1.40) приведенный алгоритм, как и в случае линейного поиска, находит совпадающий элемент с наименьшим индексом.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]