Skip to content

Latest commit

 

History

History
97 lines (64 loc) · 7.43 KB

File metadata and controls

97 lines (64 loc) · 7.43 KB

Полиномиальный скользящий хэш

Хэш-функция

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

Основным применением хеширования является эффективная проверка равенства ключей путем сравнения их хеш-суммой.

Коллизия возникает, когда два разных ключа имеют одинаковый отпечаток. Способ обработки коллизий имеет решающее значение в большинстве приложений хэширования. Хеширование особенно полезно при построении эффективных практических алгоритмов.

Скользящий хеш

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

Несколько хеш—функций позволяют очень быстро вычислять переходящий хеш-код - новое значение хеш-кода быстро вычисляется, учитывая только следующие данные:

  • старое значение хеш-кода,
  • старое значение, удаленное из окна,
  • и новое значение, добавленное в окно.

Полиномиальное хеширование строк

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

Алгоритм поиска строк Рабина–Карпа часто объясняется с помощью очень простой скользящей хэш-функции, которая использует только умножение и сложение - полиномиальный скользящий хэш:

H(s0, s1, ..., sk) = s0 * pk-1 + s1 * pk-2 + ... + sk * p0

где p - константа, а (s1, ... , sk) - входные символы.

Например, мы можем преобразовать короткие строки в ключевые числа, умножив цифровые коды на степени константы. Трехбуквенное слово ace можно преобразовать в число, вычислив:

ключ = 1 * 262 + 3 * 261 + 5 * 260

Чтобы избежать манипулирования огромными значениями H, вся математика выполняется по модулю M.

H(s0, s1, ..., sk) = (s0 * pk-1 + s1 * pk-2 + ... + sk * p0) mod M

Тщательный выбор параметров M, p важен для получения “хороших” свойств хэш-функции, т.е. низкой частоты коллизий.

Желательным свойством этого подхода является использование всех символов во входной строке. Вычисленное значение ключа затем может быть хэшировано в индекс массива обычным способом:

function hash(key, arraySize) {
  const base = 13;

  let hash = 0;
  for (let charIndex = 0; charIndex < key.length; charIndex += 1) {
    const charCode = key.charCodeAt(charIndex);
    hash += charCode * (base ** (key.length - charIndex - 1));
  }

  return hash % arraySize;
}

Метод hash() не так эффективен, как мог бы быть. Помимо преобразования символов, в цикле есть два умножения и сложение. Мы можем исключить одно умножение, используя метод Хорнера:

a4 * x4 + a3 * x3 + a2 * x2 + a1 * x1 + a0 = (((a4 * x + a3) * x + a2) * x + a1) * x + a0

Другими словами:

Hi = (P * Hi-1 + Si) mod M

Функция hash() не может обрабатывать длинные строки, поскольку значение hashVal превышает размер int. Обратите внимание, что размер ключа всегда оказывается меньше размера массива. В методе Хорнера мы можем применять оператор по модулю (%) на каждом шаге вычисления. Это дает тот же результат, что и однократное применение оператора по модулю в конце, но позволяет избежать переполнения.

function hash(key, arraySize) {
  const base = 13;

  let hash = 0;
  for (let charIndex = 0; charIndex < key.length; charIndex += 1) {
    const charCode = key.charCodeAt(charIndex);
    hash = (hash * base + charCode) % arraySize;
  }

  return hash;
}

Полиномиальное хеширование обладает свойством плавного перехода: хэш-сумма может эффективно обновляться при добавлении или удалении символов в концах строки (при условии, что сохранен массив степеней p по модулю M достаточной длины). Популярный алгоритм сопоставления Рабина–Карпа основан на этом свойстве

Ссылки