Новосибирский Государственный Университет
Опубликован: 08.11.2006 | Доступ: свободный | Студентов: 1943 / 96 | Оценка: 4.27 / 4.09 | Длительность: 12:16:00
Специальности: Программист
Лекция 13:

Поиск

< Лекция 12 || Лекция 13: 1234 || Лекция 14 >
Аннотация: Введение. Поиск и другие операции над таблицами. Последовательный поиск. Логарифмический поиск в статических таблицах. Бинарный поиск. Оптимальные деревья бинарного поиска. Логарифмический поиск в динамических таблицах. Сбалансированные сильно ветвящиеся деревья.

Введение

Задача поиска является фундаментальной в комбинаторных алгоритмах, так как она формулируется в такой общности, что включает в себя множество задач, представляющих практический интерес. При самой общей постановке "Исследовать множество T с тем чтобы найти элемент, удовлетворяющий некоторому условию C ", о задаче поиска едва ли можно сказать что-либо стоящее. Удивительно, однако, что достаточно незначительных ограничений на структуру множества T, чтобы задача стала интересной: возникает множество разнообразных стратегий поиска различной степени эффективности. Мы сделаем некоторые предположения о структуре множества T, позволяющие исследовать T {\rm O}(\log n) или {\rm O}(1). Большинство алгоритмов поиска попадает в одну из трех категорий, характеризуемых временем поиска {\rm O}(n).

Поиск и другие операции над таблицами

Любой способ поиска оперирует с элементами, которые будем называть именами, взятыми из множества имен S - оно называется пространством имен. Это пространство имен может быть конечным или бесконечным. Самыми распространенными пространствами имен являются множества целых чисел с их числовым порядком (нумерацией), и множества последовательностей символов над некоторым конечным алфавитом с их лексикографическим (то есть словарным) порядком. Каждый из алгоритмов поиска, обсуждаемых в этой лекции, основан на одном из трех следующих предположений о пространстве S.

Предположение 1. На S определен линейный порядок, называемый естественным порядком и обозначаемый знаком <. Такой порядок имеет следующие свойства.

  1. Любые два элемента x,y \in S сравнимы, то есть должно выполняться в точности одно из трех условий: x < y, x =
y, y < x.
  2. Порядок обладает транзитивностью, то есть если x < y и y < z, то x < z для любых элементов x,y,z \in S. Мы используем обозначения >, \leqslant, \geqslant в очевидном смысле. При анализе эффективности алгоритма поиска полагаем, что исход ( <, = или > ) зависит от сравнения.

Предположение 2. Каждое имя в S есть последовательность символов или цифр над конечным линейно упорядоченным алфавитом A = \{ a_1,a_2,\ldots,a_c \}. Естественным порядком на S является лексикографический порядок, индуцированный линейным порядком на A. Мы полагаем, что исход ( <, = или > ) сравнения двух символов (не имен) получается за время, не зависящее от \left| S \right| или n.

Предположение 3. Имеется функция {h\colon S \to \{ 0,1,\ldots,m - 1}\}, которая равномерно отображает пространство имен S в множество \{ 0,1,\ldots,m - 1\}, то есть все целые i,0 \leqslant i \leqslant m
- 1, приблизительно с одинаковой частотой являются образами имен из S при отображении h. Мы полагаем, что функция h не зависела от \left| S \right|, это с теоретической точки зрения выглядит шатко, но с практической - довольно реально.

Как уже было отмечено, поиск производится не в самом пространстве S имен, а в конечном подмножестве T = \{ x_1,x_2,\ldots,x_n
\} множества S, называемом таблицей. На большинстве таблиц, которые мы рассматриваем, определен линейный порядок, называемый табличным порядком: ему соответствует нижний индекс имени (то есть x_1 есть первое имя в таблице, x_2 - второе и тому подобное). Табличный порядок часто совпадает с естественным порядком, определенным на пространстве имен, однако такое совпадение не обязательно.

Мощность таблицы T обычно намного меньше, чем мощность пространства имен S, даже если S конечно.

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

Мы будем предполагать, что имена появляются в таблице не больше одного раза (исключение составляет переходный период, в течение которого заносится новое имя; в таблице допускается два вхождения одного имени). В большинстве случаев вследствие такого предположения таблица с n именами имеет ровно n ячеек. Однако важный класс алгоритмов, основанных на вычислении адреса, опирается на предположение о том, что таблица содержит больше ячеек, чем имен. Эти алгоритмы должны четко принимать во внимание наличие пустых ячеек.

Существует ряд синонимов для объектов, именуемых здесь таблицей и именем. В обработке данных существуют файлы, элементами которых являются записи ; каждая запись есть последовательность полей, одно из которых (участвующее в поиске) называется ключом. Если сам файл проходится во время поиска, "файл" и "ключ" представляют собой то, что мы называем "таблицей" и "именем" соответственно. (Эта терминология несколько двусмысленна, поскольку понятие "ключ" можно отнести либо к самой ячейке, либо к содержимому ячейки.) Однако при поиске в большом файле часто не подразумевается просмотр самого файла; вместо этого поиск осуществляется на справочнике или указателе файла. При успешном поиске найденная в указателе отдельная запись указывает на соответствующую запись в файле. В таком типе организации файлов нашему понятию таблицы соответствует указатель или справочник.

Мы рассматриваем только четыре табличные операции: поиск, включение, исключение и распечатка. Подробное определение того, что должны делать эти операции над таблицей T = \{ x_1,x_2,\ldots,x_n \}, зависит от структуры данных, использованной для реализации таблицы.

поиск z: если z \in T, то отметить его указателем, то есть переменной i присвоить такое значение, что z = x_i ; в противном случае указать, что z \notin T ;

включение z: если z \notin T, то поместить его на соответствующее место.

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

включить z на iместо: включить z сразу после имени x_{i -1}. До включения T = \{ x_1,\ldots,x_{i -
1},\ldots,x_{i - 1} z,x_i,\ldots,x_n \}.

исключить z: если z \in T, то исключить его.

Как и включение, исключение иногда реализуется процедурой поиска для получения места z и последующей процедурой:

исключить с i -го места: исключить x_i из T.До исключения T = \{ x_1,\ldots,x_{i -
1},x_i,x_{i + 1},\ldots,x_n \} \\ & После исключения T = \{
x_1,\ldots,x_{i - 1},x_{i + 1},\ldots,x_n \}

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

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

распечатка: & напечатать все имена из T в их естественном порядке

Среди всех операций, которые можно производить над таблицами, четыре, рассматриваемые в этой лекции (поиск, включение, исключение и распечатка), и сортировка ( "Сортировка (часть 1)" "Сортировка (часть 2)" ) - наиболее важные.

< Лекция 12 || Лекция 13: 1234 || Лекция 14 >