- •Введение
- •Содержание и структура пособия
- •Задачи поиска в информатике
- •Задача поиска в таблице
- •Поиск в массивах
- •Линейный поиск
- •Бинарный поиск
- •Вопросы и упражнения
- •Алгоритмы сортировки массивов
- •Задачи сортировки таблиц и массивов
- •Простые алгоритмы сортировки
- •Алгоритм пузырька (BubbleSort)
- •Алгоритм выбора (SelectionSort)
- •Алгоритм вставок (InsertionSort)
- •Общая характеристика простых алгоритмов
- •Алгоритм Шелла (ShellSort)
- •Алгоритм быстрой сортировки (QuickSort)
- •Алгоритм пирамидальной сортировки (HeapSort)
- •Алгоритмы сортировки слиянием (MergeSort)
- •Задача внешней сортировки
- •Сравнение алгоритмов сортировки
- •Вопросы и упражнения
- •Сортировка и поиск с использованием деревьев
- •Задача поиска со вставкой
- •Бинарные деревья поиска
- •Var t: Tree; {Кореньдерева}
- •X: KeyType; {Искомый ключ}
- •Var found: Boolean {Найдено или вставлено?}
- •Страничные деревья поиска
- •Использование b-деревьев в базах данных
- •Вопросы и упражнения
- •Специальные методы сортировки и поиска
- •Поразрядная сортировка
- •Поиск в словаре и нагруженные деревья
- •Вопросы и упражнения
- •Хеширование
- •Основные понятия хеширования
- •Способы построения хеш-функций
- •Общие требования к хеш-функциям
- •Алгоритм деления
- •Алгоритм середины квадрата
- •Алгоритм умножения
- •Хеширование строковых ключей
- •Методы разрешения коллизий
- •Алгоритм линейных проб
- •Алгоритм квадратичных проб
- •Алгоритм двойного хеширования
- •Алгоритм списков в динамической памяти
- •Алгоритм Уильямса
- •Эффективность хеширования и сравнение с другими методами поиска
- •Вопросы и упражнения
- •Дополнительные вопросы поиска
- •Определение порядковых статистик
- •Задача поиска в строке
- •Постановка задачи и «прямое» решение
- •Алгоритм Кнута, Морриса и Пратта
- •Алгоритм Бойера – Мура
- •Вопросы и упражнения
- •Заключение
- •Библиографический список
Бинарный поиск
Теперь предположим, что массив Aявляетсясортированным, т.е. значения в нем расположены по возрастанию значений ключа.
В этом случае можно применить совершенно иной, более быстрый алгоритм поиска, не требующий проверки всех подряд элементов. Вместо этого сравним искомый ключ xсо значением среднего по порядку элемента массива, т.е. элемента с индексом(n+1)/2. Еслиnчетное, то неважно, какой из двух средних элементов будет выбран.
Если xокажется меньше, чем проверяемый средний элемент, то ясно, что искомое значение может содержаться только в левой половине массива (или нигде). И наоборот, еслиxбольше проверяемого элемента, то поиск надо продолжать в правой половине массива. В том и другом случае выполнение одной проверки позволяет в два раза уменьшить размер той части массива, в которой следует искатьx. Далее та же процедура применяется к выбранной половине массива (т.е. проверяется элемент с индексом либо(n+1)/4, либо3(n+1)/4) и т.д., пока не будет найден нужный элемент либо не обнаружится его отсутствие.
Описанный алгоритм называется бинарным поискомв массиве. Соответствующая функция поиска приведена ниже.
function BinarySearch(A: TableType, x: KeyType
): Integer;
var
i, j, q: Integer;
begin
i := 1; j := N;
repeat
q := (i + j) div 2;
if A[q] < x then
i := q + 1
else
j := q – 1;
until (A[q] = x) or (i > j);
if A[q] = x then BinarySearch := q {Успех}
else BinarySearch := 0; {Неудача}
end; {BinarySearch}
Переменные iиjиграют роль подвижных границ той части массива, в которой может находиться значение искомого ключа. Каждое сравнение приводит к сужению вдвое интервала поиска за счет перемещения одной из этих границ.
Оценим эффективность алгоритма. Каждая итерация цикла (включающая проверку значения и смещение одной из границ) сокращает интервал поиска по меньшей мере в два раза. Поиск завершается, когда интервал сведется к одному элементу. Для этого придется выполнить не более log2nитераций. Таким образом, можно сказать, что алгоритм бинарного поиска имеетлогарифмическуюоценку эффективностиT(n) = O(log(n)).
Сопоставим это с числом итераций линейного поиска, примерно равным n. Соответствующие значения для разныхnприведены в табл.2.1.
Таблица 2.1
n |
10 |
100 |
1000 |
10 000 |
100 000 |
1 000 000 |
log2(n) |
3 |
7 |
10 |
13 |
17 |
20 |
Если учесть, что одна итерация бинарного поиска заметно сложнее, чем одна итерация линейного поиска, то можно сделать примерно следующие выводы. Для очень маленьких таблиц, имеющих около 10 элементов, использование бинарного поиска не дает существенного выигрыша по сравнению с линейным. Для таблиц размером около 100 выигрыш уже ощутим, но необходимость использования бинарного поиска еще можно считать спорной (потому что на современных процессорах экономия составит не более нескольких микросекунд). Однако при размерах от 1000 и выше спорить уже не приходится, поскольку бинарный поиск работает просто несравнимо лучше, чем линейный.
Не будем только забывать, что для применимости бинарного поиска требуется, чтобы массив был сортированным.