
- •Структура данных и ее классификация.
- •«Дерево», его классификация, примеры, способы перемещения
- •«Хэш-таблицы»
- •Способы реализации «хэш-функций»
- •Разрешение коллизий
- •Алгоритмы и свойства
- •Рекурсия
- •«Разделяй и властвуй», «Ханойские башни»
- •Динамическое прогриммирование
- •Сортировка
- •Выбор, вставка, пузырьки и Шелла
- •По указателях и индексам, распределяющего подсчета
- •Быстрая сортировка
- •Слияния
- •Очередь по преоритету
- •Пирамидальная сортировка
- •Порязрядная сортировка
- •Алгоритм поиска
- •Суть последовательно, бинарного и интерполяционнного поиска
Алгоритм поиска
Общая классификация алгоритмов поиска
Все методы можно разделить на статические и динамические. При статическом поиске массив значений не меняется во время работы алгоритма. Во время динамического поиска массив может перестраиваться или изменять размерность.
Представьте себе, что Вы ищете слово в словаре. Как бы Вы его не искали, Ваш агоритм обязательно будет статическим, так как сам словарь ( массив слов ) не будет изменяться во время поиска. Если конечно не выдирать из него страницы. Примером динамического поиска может служить попытка найти определенную карту в колоде. Откладывая в сторону ненужные карты, Вы облегчаете себе задачу поиска, уменьшая количества оставшихся карт в колоде, которые еще нужно перебрать, тем самым перестраивая массив значений во время поиска!
Так же методы поиска можно разделить на методы, использующие истинные ключи и на методы, работающие по преобразованным ключам. В данном случае "ключем" называют то значение, которое мы ищем.
Поиск в колоде карт - поиск по истинным ключам, то есть имеете дело с тем, что есть. Поиск в словаре - поиск по преобразованным ключам, так как все слова отсортированы в алфавитном порядке, то есть массив значений изменен перед началом поиска. Этот порядок создан специально для облегчения поиска и вовсе не является естественным для списка слов!
Кстати, привычный нам алфавитный порядок слов, не всегда казался людям естественным и является изобретением не очень древним.
Ну и еще вариант классификации - методы основанные на сравнении самих значений и методы, основанные на их цифровых свойствах. Так называемые методы хэширования.
Рассматриваемые в данном обзоре алгоритмы являются комбинациями первых двух способов классификации. О методе хэширования я лишь упомяну исключительно из академического интереса, так как он не входит в круг рассматриваемых здесь задач.
Представьте себе, что нам надо найти определенную карту в колоде. Для этого мы выбрали довольно нестандартный способ, мы придумали такую функцию, которая вычисляет номер нужной карты в колоде. Например
f("крестовая дама") = 5 , а f("туз пик")=12
То есть, подставив в функцию искомое значение, мы получаем местоположение этого значения в нашем массиве. Вот здорово! Это же самый что ни на есть ПРЯМОЙ доступ , по сравнению с ПОСЛЕДОВАТЕЛЬНЫМ перебором всех ( или некоторых ) значений в искомом массиве.
Этот метод и называется методом хэширования. Все бы хорошо, но вот беда, функция f(К) должна определять ОДНОЗНАЧНОЕ соответствие для каждого значения в массиве, а находить подобные функции довольно сложно.
Подробное рассмотрение алгоритмов
Попытаемся решить простейшую задачу - найти нужное значение в массиве. На этом первом примере мне хочется показать, как оптимальность решения зависит от того, в каком массиве мы будем искать.
Перед Вами колода игральных карт, в ней , как правило, 54 карты ( ну или 36 ). Карты лежат в беспорядке. Необходимо найти определенную карту, например пикового короля. Что Вы предпримете? Думаю, что догадаться нетрудно, первое, что приходит в голову, это последовательно перебирать все карты, до тех пор пока нужная не найдется. При самом плохом стечении обстоятельств Вам придется перебрать все карты в колоде , что на самом деле не так долго, если честно.
Попробуем немного изменить условие. Искать нам надо не карту, а конверт с определенным адресом. Конвертов этих перед Вами лежит немерянное количество, если окинуть взглядом заваленные столы, ну несколько сотен как минимум. Нет, нет, не пожимайте удивленно плечами, задача не надуманная, а самая что ни на есть реальная. Если вдруг кто-нибудь ( а мир так удивительно тесен! ) знаком с Константиновым Николаем Николаевичем, тот скорее всего знаком с этой задачей не понаслышке. Итак, я отвлеклась, перед нами несколько сотен конвертов с именами, нужно найти вполне определенный конверт. Способ, только что опробованный на колоде карт, очень скоро утомит. Вряд ли кто в этом сомневается, не правда ли? :о)
А вот если предварительно все эти конверты разложить в алфавитном порядке, то дальнейшая работа по нахождению вполне определенного имени уже не представляется такой ужасной! Конечно, на сортировку необходимо затратить вполне определенные силы и время, но они окупятся при многоразовом поиске, вот что самое главное
Вспомнив пример с картами, отметим, что в том случае тратить время на предварительную сортировку колоды вряд ли стоит...
Итак, мы можем сделать первый и очень важный вывод - оптимальность метода поиска зависит от размера массива, в котором мы ищем! Прямой перебор всех значений прост в понимании, легок в исполнении и достаточно быстр на малых массивах данных. Насчет легкости и простоты , это не лирика, это весомый аргумент, ведь Вам после того, как будет выбран определенный метод, необходимо еще формализовать его и закодировать. В итоге программиста инетересует код. Не будем об этом забывать.
Итак, все это в совокупности позволяет сказать, что метод прямого перебора оптимален для малых массивов. Если же массив данных достаточно велик, то оптимальность поиска достигается предварительной сортировкой значений в массиве.
Ну что же, с задачей поиска при малом количестве значений мы разобрались, она достаточно тривиальна. Давайте займемся поиском в о-о-очень длинном массиве... Это гораздо интереснее. Итак, приняв все вышесказанное за истину, мы отсортировали наш массив. Все значения лежат в некотором порядке. Можно искать! И, собственно, что?... Как искать-то?
Существует несколько классических способов поиска значения в отсортированном массиве. Мы рассмотрим три способа. Они были предложены в 60-х годах и мало изменились в наше время. Один из них очень известный, ведь Вам наверняка приходилось слышать такие названия как "метод дихотомии", "бинарного дерева" или "метод половинного деления", что собственно одно и тоже. Вот с него и начнем.