Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ТОИП лекции.doc
Скачиваний:
100
Добавлен:
17.03.2015
Размер:
6.17 Mб
Скачать

§10. Чистый бинарный поиск

Поиск данного вида представляет собой обобщение двоичного поиска. Сформулируем задачу чистого бинарного поиска следующим образом.

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

Для построения такого алгоритма предположим, что записи упорядочены по возрастанию значений pi и разобьем каждое из множеств непроверенных записей посередине (если число записей в множестве нечетно, то для определенности будем относить серединную запись к подмножеству с меньшими значениями pi). Пример такого разбиения приведен на рис. 2.8.

Рис.2.8. Пример чистого бинарного поиска

Для приведенного примера на первом шаге алгоритма выясняется, «равен ли аргумент поиска пяти или больше», т.е. производится первое сравнение. Пусть ответом на поставленный вопрос будет «нет», тогда следующим вопросом (второе сравнение) будет: «тройка или четверка?» и т.д.

Прямой подсчет среднего числа сравнений для рассмотренного примера дает: C10’=4∙(1/55 + 2/55) + 3∙(3/55 + 4/55 + 5/55) + 4∙(6/55 + 7/55) + 3∙(8/55 + 9/55 + 10/55) = 3,291.

Рассмотренная задача соответствует удачному поиску. Однако, если сравнить этот алгоритм с алгоритмом двоичного поиска, то легко заметить, что его поведение в точности соответствует случаю неудачного двоичного поиска.

Сравнивая задачу чистого бинарного поиска с рассмотренной в разделе 1 задачей экономного кодирования, легко убедиться, что они идентичны. Дерево поиска соответствует при этом бинарному кодовому дереву. Следовательно, для улучшения алгоритма чистого бинарного поиска можно воспользоваться процедурами экономного кодирования (Шеннона-Фано или Хафмана). Так, применение этих процедур к рассматриваемому примеру обеспечивает среднее число сравнений, равное 3,145. При этом, ввиду оптимальности процедуры Хафмана, это число не может быть меньше.

§11. Помехоустойчивый поиск

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

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

Например, предположим, что в роли ключей выступают слова, которые могли быть слегка искажены, и мы хотели бы найти нужную запись, несмотря на эту ошибку. Если сделать две копии файла, в одной из которых ключи расположены в обычном алфавитном порядке, а в другой они упорядочены справа налево (как если бы слова были прочитаны наоборот), искаженный аргумент поиска в большинстве случаев совпадает до половины своей длины или более с записью одного из этих двух файлов. Таким способом удается отыскать возможные претенденты на искомую запись.

Другая идея решения этой задачи состоит в том, чтобы найти некоторое преобразование аргумента в код (маску), собирающий вместе все варианты данного ключа. За рубежом нашел широкое применение следующий метод кодирования фамилий:

а) оставить первую букву; все буквы A, E, H, I, O, U, W, Y, стоящие на других местах, - вычеркнуть;

б) оставшимся буквам (кроме первой) присвоить следующие значения:

(B, F, P, V) -> 1;

(C, G, J, K, Q, S, X, Z) -> 2;

(D, T) -> 3;

L -> 4;

(M, N) -> 5;

R -> 6;

в) если в исходном имени (перед шагом а) рядом стояли несколько букв с одинаковыми кодами, пренебречь всеми, кроме первой из этой группы;

г) дописывая в случае надобности нули или опуская лишние цифры, преобразовать полученное выражение в форму «одна буква, три цифры».

Например:

Ключевое слово

Код маски

EULER

E460

GAUSS

G200

HILBERT

H416

KNUTH

K530

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