В информатике идеальная хэш-функция h для множества S — это хэш-функция , которая отображает отдельные элементы в S в множество из m целых чисел без коллизий . В математических терминах это инъективная функция .
Идеальные хэш-функции могут использоваться для реализации таблицы поиска с постоянным временем доступа в худшем случае. Идеальная хэш-функция, как и любая хэш-функция , может использоваться для реализации хэш-таблиц , с тем преимуществом, что не требуется реализовывать разрешение коллизий . Кроме того, если ключи отсутствуют в данных и если известно, что запрашиваемые ключи будут действительными, то ключи не нужно хранить в таблице поиска, что экономит место.
Недостатки идеальных хеш-функций в том, что для построения идеальной хеш-функции необходимо знать S. Нединамические идеальные хеш-функции необходимо перестраивать, если S изменяется. Для часто изменяющихся S можно использовать динамические идеальные хеш-функции за счет дополнительного пространства. [1] Требуемое пространство для хранения идеальной хеш-функции составляет O ( n ), где n — количество ключей в структуре.
Важными параметрами производительности идеальных хеш-функций являются время вычисления, которое должно быть постоянным, время построения и размер представления.
Идеальная хэш-функция со значениями в ограниченном диапазоне может использоваться для эффективных операций поиска, помещая ключи из S (или другие связанные значения) в таблицу поиска, индексированную выходными данными функции. Затем можно проверить, присутствует ли ключ в S , или найти значение, связанное с этим ключом, найдя его в его ячейке таблицы. Каждый такой поиск занимает постоянное время в худшем случае . [2] При идеальном хэшировании связанные данные могут быть прочитаны или записаны с помощью одного доступа к таблице. [3]
Важными параметрами производительности для идеального хеширования являются размер представления, время оценки, время построения и, кроме того, требование к диапазону (среднее количество сегментов на ключ в хеш-таблице). [4] Время оценки может быть таким же быстрым, как O ( 1 ) , что является оптимальным. [2] [4] Время построения должно быть не менее O ( n ) , поскольку каждый элемент в S должен быть рассмотрен, а S содержит n элементов. Эта нижняя граница может быть достигнута на практике. [4]
Нижняя граница размера представления зависит от m и n . Пусть m = (1+ε) n и h — идеальная хэш-функция. Хорошее приближение для нижней границы — Биты на элемент. Для минимального идеального хэширования, ε = 0 , нижняя граница — log e ≈ 1,44 бита на элемент. [4]
Идеальная хеш-функция для определенного множества S , которая может быть оценена за постоянное время и со значениями в небольшом диапазоне, может быть найдена рандомизированным алгоритмом за ряд операций, пропорциональных размеру S. Оригинальная конструкция Фредмана, Комлоша и Семереди (1984) использует двухуровневую схему для отображения множества S из n элементов в диапазон индексов O ( n ) , а затем отображает каждый индекс в диапазон значений хеш-функции. Первый уровень их конструкции выбирает большое простое число p (больше размера вселенной, из которой взято S ), и параметр k , и отображает каждый элемент x из S в индекс
Если k выбирается случайным образом, этот шаг, скорее всего, будет иметь коллизии, но число элементов n i , которые одновременно отображаются в один и тот же индекс i , скорее всего, будет небольшим. Второй уровень их построения назначает непересекающиеся диапазоны O ( n i 2 ) целых чисел каждому индексу i . Он использует второй набор линейных модульных функций, по одному для каждого индекса i , для отображения каждого члена x из S в диапазон, связанный с g ( x ) . [2]
Как показывают Фредман, Комлош и Семереди (1984), существует выбор параметра k, такой что сумма длин диапазонов для n различных значений g ( x ) равна O ( n ) . Кроме того, для каждого значения g ( x ) существует линейная модульная функция, которая отображает соответствующее подмножество S в диапазон, связанный с этим значением. Как k , так и функции второго уровня для каждого значения g ( x ) , могут быть найдены за полиномиальное время путем случайного выбора значений до тех пор, пока не будет найдено то, которое работает. [2]
Сама хэш-функция требует дискового пространства O ( n ) для хранения k , p и всех линейных модульных функций второго уровня. Вычисление хэш-значения заданного ключа x может быть выполнено за постоянное время путем вычисления g ( x ) , поиска функции второго уровня, связанной с g ( x ) , и применения этой функции к x . Модифицированная версия этой двухуровневой схемы с большим количеством значений на верхнем уровне может быть использована для построения идеальной хэш-функции, которая отображает S в меньший диапазон длины n + o ( n ) . [2]
Более поздний метод построения идеальной хэш-функции описан Белаццуги, Ботельо и Дицфельбингером (2009) как «хэш, смещение и сжатие». Здесь хэш-функция первого уровня g также используется для отображения элементов в диапазон целых чисел r . Элемент x ∈ S хранится в Bucket B g(x) . [4]
Затем, в порядке убывания размера, элементы каждого ведра хэшируются хэш-функцией последовательности независимых полностью случайных хэш-функций (Φ 1 , Φ 2 , Φ 3 , ...) , начиная с Φ 1 . Если хэш-функция не создает никаких коллизий для ведра, а полученные значения еще не заняты другими элементами из других ведер, функция выбирается для этого ведра. Если нет, проверяется следующая хэш-функция в последовательности. [4]
Чтобы оценить идеальную хеш-функцию h ( x ), нужно только сохранить отображение σ индекса контейнера g ( x ) на правильную хеш-функцию в последовательности, в результате чего h(x) = Φ σ(g(x)) . [4]
Наконец, для уменьшения размера представления ( σ(i)) 0 ≤ i < r сжимаются в форму, которая по-прежнему допускает оценку за O ( 1 ) . [4]
Этот подход требует линейного времени по n для построения и постоянного времени оценки. Размер представления составляет O ( n ) и зависит от достигнутого диапазона. Например, при m = 1,23 n Belazzougui, Botelho & Dietzfelbinger (2009) достигли размера представления между 3,03 бит/ключ и 1,40 бит/ключ для их приведенного в качестве примера набора из 10 миллионов записей, при этом более низкие значения требуют большего времени вычисления. Нижняя граница пространства в этом сценарии составляет 0,88 бит/ключ. [4]
Алгоритм хеширования, смещения и сжатия : (1) Разбить S на блоки B i := g −1 ({i}) ∩ S, 0 ≤ i < r (2) Сортировать блоки B i в порядке убывания в соответствии с размером |B i |(3) Инициализируем массив T[0...m-1] нулями(4) для всех i ∈[r], в порядке из (2), выполнить (5) для l ← 1,2,...(6) повторить формирование K i ← { Φ l (x)|x ∈ B i }(6) до тех пор, пока |K i |=|B i | и K i ∩{j|T[j]=1}= ∅(7) пусть σ(i):= успешный l(8) для всех j ∈ K i пусть T[j]:= 1(9) Преобразовать (σ i ) 0≤i<r в сжатую форму, сохраняя O ( 1 ) доступ.
Использование O ( n ) слов информации для хранения функции Фредмана, Комлоша и Семереди (1984) является близким к оптимальному: любая идеальная хеш-функция, которая может быть вычислена за постоянное время, требует по крайней мере количества бит, пропорционального размеру S . [5]
Для минимальных совершенных хеш-функций нижняя граница теоретико-информационного пространства равна
бит/ключ. [4]
Для идеальных хеш-функций сначала предполагается, что диапазон h ограничен n как m = (1+ε) n . С формулой, данной Белаццуги, Ботельо и Дицфельбингером (2009), и для вселенной , размер которой | U | = u стремится к бесконечности, нижние границы пространства равны
бит/ключ, минус log( n ) бит в целом. [4]
Тривиальный, но распространенный пример идеального хеширования подразумевается в адресном пространстве (виртуальной) памяти компьютера. Поскольку каждый байт виртуальной памяти является отдельным, уникальным, напрямую адресуемым местом хранения, значение начального адреса , где любой объект хранится в памяти, можно считать фактически идеальным хешем этого объекта во всем диапазоне адресов памяти. [6]
Использование идеальной хэш-функции лучше всего подходит в ситуациях, когда есть часто запрашиваемый большой набор S , который редко обновляется. Это связано с тем, что любое изменение набора S может привести к тому, что хэш-функция перестанет быть идеальной для измененного набора. Решения, которые обновляют хэш-функцию каждый раз, когда набор изменяется, известны как динамическое идеальное хэширование [1] , но эти методы относительно сложны в реализации.
Минимальная совершенная хеш-функция — это совершенная хеш-функция, которая отображает n ключей в n последовательных целых чисел — обычно числа от 0 до n − 1 или от 1 до n . Более формальный способ выражения этого таков: пусть j и k — элементы некоторого конечного множества S . Тогда h является минимальной совершенной хеш-функцией тогда и только тогда, когда h ( j ) = h ( k ) подразумевает j = k ( инъективность ) и существует целое число a такое, что диапазон h равен a .. a + | S | − 1 . Было доказано, что для минимальной совершенной хеш-схемы общего назначения требуется не менее бит/ключ. [4] Предполагая, что — набор размера, содержащий целые числа в диапазоне , известно, как эффективно построить явную минимальную совершенную хеш-функцию от до , которая использует биты пространства и которая поддерживает постоянное время вычисления. [7] На практике существуют минимальные совершенные хеш-схемы, которые используют примерно 1,56 бит/ключ, если дано достаточно времени. [8]
Хэш-функция является k -совершенной, если не более k элементов из S отображаются на одно и то же значение в диапазоне. Алгоритм «хеш, смещение и сжатие» может быть использован для построения k -совершенных хеш-функций, допуская до k коллизий. Изменения, необходимые для достижения этого, минимальны и подчеркнуты в адаптированном псевдокоде ниже:
(4) для всех i ∈[r], в порядке из (2), выполнить (5) для l ← 1,2,...(6) повторить формирование K i ← { Φ l (x)|x ∈ B i }(6) до тех пор, пока |K i |=|B i | и K i ∩{j| T[j]=k }= ∅(7) пусть σ(i):= успешный l(8) для всех j ∈ K i положим T[j]←T[j]+1
Минимальная совершенная хэш-функция F сохраняет порядок, если ключи заданы в некотором порядке a 1 , a 2 , ..., a n и для любых ключей a j и a k , j < k подразумевает F ( a j ) < F( a k ) . [9] В этом случае значение функции — это просто позиция каждого ключа в отсортированном порядке всех ключей. Простая реализация сохраняющих порядок минимальных совершенных хэш-функций с постоянным временем доступа заключается в использовании (обычной) совершенной хэш-функции для хранения таблицы поиска позиций каждого ключа. Это решение использует биты, что оптимально в условиях, когда функция сравнения для ключей может быть произвольной. [10] Однако, если ключи a 1 , a 2 , ..., a n являются целыми числами, взятыми из вселенной , то можно построить сохраняющую порядок хэш-функцию, используя только биты пространства. [11] Более того, известно, что эта граница является оптимальной. [12]
В то время как хорошо размерные хэш-таблицы имеют амортизированное среднее время O(1) (амортизированное среднее постоянное время) для поиска, вставки и удаления, большинство алгоритмов хэш-таблиц страдают от возможных худших времен, которые занимают гораздо больше времени. Худшее время O(1) (постоянное время даже в худшем случае) было бы лучше для многих приложений (включая сетевой маршрутизатор и кэши памяти ). [13] : 41
Немногие алгоритмы хэш-таблиц поддерживают худшее время поиска O(1) (постоянное время поиска даже в худшем случае). Вот некоторые из них: идеальное хэширование; динамическое идеальное хэширование ; хэширование кукушкой ; хэширование классиками ; и расширяемое хэширование . [13] : 42–69
Простая альтернатива идеальному хешированию, которая также допускает динамические обновления, — это хеширование кукушки . Эта схема сопоставляет ключи с двумя или более локациями в пределах диапазона (в отличие от идеального хеширования, которое сопоставляет каждый ключ с одной локацией), но делает это таким образом, что ключи могут быть назначены один к одному локациям, с которыми они были сопоставлены. Поиск с этой схемой медленнее, поскольку необходимо проверить несколько локаций, но тем не менее занимает постоянное время в худшем случае. [14]