Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Высокоцровневые методы информатики и првые методы информатики и программированияограммирования.doc
Скачиваний:
332
Добавлен:
01.05.2014
Размер:
14.7 Mб
Скачать

4.4 Способы построения хеш – функций Выбор хорошей хеш-функции

Хорошая хеш-функция должна (приближенно) удовлетворять предположениям равномерного хеширования: для очередного ключа все т хеш-значений должны быть равновероятны. Чтобы это предположение имело смысл, фиксируем распределение вероятностей Р на множестве U; будем предполагать, что ключи выбираются из U независимо друг от друга, и каждый распределён в соответствии с Р. Тогда равномерное хеширование означает, что

для j=0,1,…,m – 1 (4.1)

К сожалению, распределение Р обычно неизвестно, так что проверить это не­возможно (да и ключи не всегда разумно считать независимыми).

Изредка распределение Р бывает известно. Пусть, например, ключи – слу­чайные действительные числа, независимо и равномерно распределённые на про­межутке [0,1). В этом случае легко видеть, что хеш-функция h(k) = km удо­влетворяет условию (4.1).

На практике при выборе хеш-функций пользуются различными эвристи­ками, основанными на специфике задачи. Например, компилятор языка про­граммирования хранит таблицу символов, в которой ключами являются иден­тификаторы программы. Часто в программе используется несколько похожих идентификаторов (например, «pt» и «pts»). Хорошая хеш-функция будет стараться, чтобы хеш-значения у таких похожих идентификаторов были различны.

Обычно стараются подобрать хеш-функцию таким образом, чтобы её пове­дение не коррелировало с различными закономерностями, которые могут встре­титься в хешируемых данных. Например, описываемый ниже метод деления с остатком состоит в том, что в качестве хеш-значения берётся остаток от деления ключа на некоторое простое число. Если это простое число никак не связано с функцией распределения Р, то такой метод даёт хорошие результаты.

Заметим в заключение, что иногда желательно, чтобы хеш-функция удо­влетворяла условиям, выходящим за пределы требования равномерного хеши­рования. Например, можно стараться, чтобы «близким» в каком-либо смысле ключам соответствовали «далёкие» хеш-значения (это особенно желательно при использовании описанной в разделе 4.5 линейной последовательности проб).

Ключи как натуральные числа

Обычно предполагают, что область определения хеш-функции – множество целых неотрицательных чисел. Если ключи не являются натуральными числами, их обычно можно преобразовать к такому виду (хотя числа могут получиться большими). Например, последовательности символов можно интерпретировать как числа, записанные в системе счисления с подходящим основанием: иденти­фикатор «pt» – это пара чисел (112,116) (таковы ASCII-коды букв «р» и «t»), или же число (112128) + 116 = 14452 (в системе счисления по основанию 128). Далее мы всегда будем считать, что ключи – целые неотрицательные числа.

Деление с остатком

Построение хеш-функции методом деления с остатком (division method) состоит в том, что ключу k ставится в соответствие остаток от деления k на m, где т – число возможных хеш-значений:

h(k)k mod m.

Например, если размер хеш-таблицы равен m = 12 и ключ равен 100, то хеш-значение равно 4.

При этом некоторых значений m стоит избегать. Например, если m = 2Р, то h(k) –это просто р младших битов числа k. Если нет уверенности, что все комбинации младших битов ключа будут встречаться с одинаковой частотой, то степень двойки в качестве числа т не выбирают. Нехорошо также выбирать в качестве т степень десятки, если ключи естественно возникают как десятич­ные числа: ведь в этом случае окажется, что уже часть цифр ключа полностью определяет хеш-значение. Если ключи естественно возникают как числа в си­стеме счисления с основанием 2Р, то нехорошо брать m = 2Р – 1, поскольку при этом одинаковое хеш-значение имеют ключи, отличающиеся лишь перестановкой «2р-ичных цифр».

Хорошие результаты обычно получаются, если выбрать в качестве m про­стое число, далеко отстоящее от степеней двойки. Пусть, например, нам надо поместить примерно 2000 записей в хеш-таблицу с цепочками, причем нас не пугает возможный перебор трёх вариантов при поиске отсутствующего в таб­лице элемента. Что ж, воспользуемся методом деления с остатком при длине хеш-таблицы m = 701. Число 701 простое, 701 ~ 2000/3, и до степеней двойки от числа 701 тоже далеко. Стало быть, можно выбрать хеш-функцию вида

h(k) = k mod 701.

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