Построение хеш-функций для строк
Гоша: Как вычислять хеш-функцию для целых чисел — ясно. А как вычислять хеш-функцию для строк?
Тимофей: Существует метод, который называется полиномиальный хеш, где хеш строки
s длины
n вычисляются по формуле:
h2(s)=(s0an−1+s1an−2+⋯+sn−2a+sn−1)modm.
Где
s0,s1,...,sn−1 — коды символов (например, ASCII-коды), а
m и
a — выбранные константы.
Тимофей: Нужно
a подбирать таким образом, чтобы при изменении одного символа значение функции сильно менялось. С этим связано одно из свойств, которыми должна обладать хорошая хеш-функция. Про эти свойства я расскажу чуть позже.
Хотим, чтобы все значения
s⋅amodm,0⩽s<m были различными. На самом деле для этого достаточно, чтобы
a и
m были взаимно простыми.
Обычно в качестве
a берут какое-то простое число.
Для избежания коллизий, если строки короткие, лучше выбирать
a побольше. Иначе значения будут скапливаться в начале массива. Если строки длинные, выбор величины
a не так важен. В этом случае в сумму будут входить значения
a в достаточно больших степенях.
Алла: А можешь привести пример?
Тимофей: Вычислим хеш от строки “ABACB”. ASCII-коды символов “A”, “B” и “C” равны 65, 66 и 67.
В качестве констант возьмём:
a=3, а
m=97.
Тогда значение хеш-функции вычисляется так:
(65⋅34+66⋅33+65⋅32+67⋅31+66⋅30)mod97=42. Полиномиальный хеш можно вычислить эффективно с использованием метода Горнера:
h2(s)=((((s0a+s1)a+s2)a+⋯+sn−2)a+sn−1)modm. Может воспользуемся методом Горнера для нашего примера:
((((65⋅3+66)⋅3+65)⋅3+67)⋅3+66)mod97=42. Тимофей: При использовании полиномиального хеширования значение хеш-функции любой строки можно вычислить за константное время. Для этого нужно сделать предобработку, которая занимает
O(n). Про этот метод вы узнаете немного позже, когда я буду рассказывать про специальные алгоритмы работы со строками.