Табличные структуры
[Оглавление] [<< страница] [>>страница]


   6.2. Выбор функции расстановки
 

При выборе функции расстановки f, отображающей множество ключей k в адреса аi, i = 0, 1, ..., N - 1, где N — размер таблицы, желательно, чтобы она не только сокращала число коллизий, но не допускала скучивания ключей в отдельных частях таблицы. Поэтому ее подбирают из условия случайного и возможно более равномерного отображения ключей в адреса хранения. Таблицы, построенные по такому принципу, называют таблицами со случайным перемешиванием (хеш-таблицами), а вычисление адресов — хешированием.

Функция расстановки f(k) должна иметь значения между О и N -1. По этой причине ее часто определяют в виде f(k) = q(k) mod N, где q(k) — функция, принимающая целочисленные значения. Тогда существуют два вида коллизий:

Существует правило Люма : доля коллизий по модулю уменьшается, если размером таблицы выбрать целое N, не имеющее делителей, меньших 20. N можно взять, например, простым, но это не обязательно.

Функция q(k) должна обеспечивать хорошее начальное распределение адресов по всей таблице. Для выбора такой функции нет готовых рецептов. Во многом это определяется решаемой задачей. Полезно построить несколько таких функций и моделировать их поведение при решении задачи.

Метод деления. В методе деления в качестве значения хеш-функции используется остаток от деления ключа на некоторое целое число М: А = kmodM или а = q(k)modM. Эффективность рассеивания по таблице во многом зависит от значения М. Плохо, если М является степенью основания системы счисления ключа или 2, при М = 28 — это значение последнего символа при символьном ключе. Лучше, если М является простым числом. Очевидно, что в этом случае число возможных адресов равно М (0, 1, ..., М - 1), все ключи, равные (к + i*M), i = 0, 1, ..., будут конфликтными.

Рассмотрим таблицу, в которой в качестве ключей записей используются фами-лии студентов учебной группы. Используем для вычисления адреса входа в таблицу только первую букву фамилии (заглавная буква русского алфавита). В русском алфавите 32 буквы, коды прописных букв имеют значения С, = 128, 129, ..., 159. Если в качестве адреса взять а = Ci-128, то а = 0, 1, ..., 31. Если список учебной группы содержит всего 17 фамилий, то по методу деления адреса могут быть вычислены как ai = (Сi-128)modl7. Фамилии, начинающиеся с А и С, Б и Т, ... будут конфликтными по модулю.

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

Метод умножения. Представим ключ в виде двоичною числа. Возьмем некоторую дробь р, умножим дробь р на k и возьмем дробную часть этого произведения (р*к). Затем умножим ее на М и возьмем целую часть. Хорошие результаты получаются, если в качестве р взять «золотое сечение», равное 0, 6180339887.

Рассмотренные два метода — метод деления и метод умножения, являются во многих случаях наилучшими.

Метод середины квадратов. Значение ключа представляется целым двоичным числом и возводится в квадрат. За адрес записи А принимается m бит средней части результата к2. Этот метод очень близок методу умножения, однако по многим параметрам уступает ему.

Преобразование системы счисления. Пусть ключ выражен в некоторой р-ичной системе счисления: к = а0 + а1р + а2р2 + … . Функция t(k), используя те же коэффициенты аi, в q-ичной системе счисления вычисляет значение полинома t(k) = ao + а1q+a2q2+…+as-1qs-1 для 5 младших цифр ключа, р и q — положительные числа, р < q, либо вычисляет t(k) с использованием всех коэффициентов, затем оставляют s младших цифр:
27130410 ≥ 2*135 + 7*134 +1*133+3*132+0*13+4*130=945221, взяв, младшие 4 цифры, получим адрес 5221.

Метод слияния (метод свертки). Ключ разбивается на не¬сколько отрезков (частей) постоянной длины, затем эти части арифметически или логически склады-ваются. Символьные ключи перед разбивкой могут преобразоваться в двоичный код. Пример: ключ 271304 = > 271 + 304 = 575. Естественно, могут быть предложены другие способы разбивки на части.

Метод деления многочленов. Пусть к выражено в двоичной системе счисления к =bn2n + bn-1 2n-1+…+b020.

Используя те же коэффициенты, представим k в виде многочлена r(t) = bntn+bn-1tn-1+…+b0t0. Найдем остаток от деления r(t) на постоянный для всех ключей многочлен c(t): c(t) =cmtm+cm-1tm-1+…+c1t+c0.

Этот остаток, опять рассматриваемый в двоичной системе счисления, и используем в качестве значения A =f(k). Этот метод трудоёмок, поэтому находит реализацию аппаратным или микропрограммным способом.

Методы вычисления хеш-функции и методы вычисления последовательностей псевдослучайных чисел имеют много общего. Отсюда одно из названий функции расстановки — функция рандомизации. Получение очередного псевдослучайного числа не что иное, как вычисление значения хеш-функции от последнего (или двух последних) значения последовательности.

[Оглавление] [<<страница] [>>страница] [В начало ]