Идеальное хеширование — различия между версиями
(добавлен псевдокод) |
|||
| Строка 1: | Строка 1: | ||
| − | '''Двойное хеширование | + | '''Двойное хеширование''' – метод борьбы с возникающими коллизиями при [[Открытое_и_закрытое_хеширование#Закрытое хеширование|закрытом хешировании]], в котором хеш-таблица заполняется равномерней чем при [[Открытое_и_закрытое_хеширование#Линейное разрешение коллизий|линейном разрешении коллизий]] коллизий, что способствует уменьшению размеров кластеров. |
| − | < | + | ==Принцип двойного хеширования== |
| − | <tex> | + | При двойном хешировании используются две независимые хеш-функции <tex> h_1(k) </tex> и <tex> h_2(k) </tex>. Пускай <tex> k </tex> это наш ключ, <tex> m </tex> размер нашей таблицы, <tex> mod \; m </tex> это остаток от деления на <tex> m </tex>, тогда сначала исследуется ячейка с адресом <tex> h_1(k) </tex>, если она уже занята рассматривается <tex> (h_1(k) + h_2(k)) \; mod \; m </tex>, затем <tex> (h_1(k) + 2 \cdot h_2(k)) \; mod \; m </tex> и т.д. В общем случае идёт проверка последовательности ячеек <tex> (h_1(k) + i \cdot h_2(k)) \; mod \; m </tex> где <tex> i = (0, 1, \; ... \;, m - 1) </tex> |
| − | </ | + | |
| + | ==Выбор хеш-функций== | ||
| + | <tex> h_1 </tex> может быть обычной хеш-функцией. Однако что бы в случаях коллизий была проверенна вся хеш-таблица, <tex> h_2 </tex> должна возвращать значения: | ||
| + | *не равные <tex> 0 </tex> | ||
| + | *независимые от <tex> h_1 </tex> | ||
| + | *взаимно простые с величиной хеш-таблицы | ||
| + | |||
| + | Например, если размер таблицы равен <tex> m </tex>, то в качестве <tex> h_2 </tex> можно использовать функцию вида <tex> h_2(k) = k \; mod \; (m-1) + 1 </tex> | ||
[[Файл: Вставка при двойном хэшировании.svg.jpeg|thumb|right|Вставка при двойном хешировании]] | [[Файл: Вставка при двойном хэшировании.svg.jpeg|thumb|right|Вставка при двойном хешировании]] | ||
| − | + | ==Пример== | |
| − | + | Показана хеш-таблица размером 13 ячеек, в которой используются вспомогательные функции: | |
| − | + | <center> | |
| + | <tex> h(k,i) = (h_1(k) + i \cdot h_2(k)) \; mod \; 13 </tex> | ||
| + | </center> | ||
<center> | <center> | ||
| Строка 28: | Строка 37: | ||
==Простая реализация== | ==Простая реализация== | ||
| + | Пускай у нас есть некоторый объект <tex> item </tex>, в котором определено поле <tex> key </tex>, от которого можно вычислить хеш-функции <tex> h_1(key)</tex> и <tex> h_2(key) </tex> | ||
| + | |||
| + | Так же у нас есть таблица <tex> table </tex> величиной <tex> m </tex> состоящая из объектов типа <tex> item </tex>. | ||
| + | |||
===Вставка=== | ===Вставка=== | ||
<pre>insert(item){ | <pre>insert(item){ | ||
| Строка 37: | Строка 50: | ||
return | return | ||
} | } | ||
| − | x = (x + y) | + | x = (x + y) mod m |
} | } | ||
error() //ошибка, требуется увеличить размер таблицы | error() //ошибка, требуется увеличить размер таблицы | ||
| Строка 52: | Строка 65: | ||
else | else | ||
return null | return null | ||
| − | x = (x + y) | + | x = (x + y) mod m |
} | } | ||
return null | return null | ||
| Строка 58: | Строка 71: | ||
==Реализация с удалением== | ==Реализация с удалением== | ||
| + | Что бы наша хеш-таблица поддерживала удаление, требуется добавить массив <tex>deleted</tex> типов <tex>bool</tex>, равный по величине массиву <tex>table</tex>. Теперь при удалении мы просто будем помечать наш объект ''как удалённый'', а при добавлении как ''не удалённый'' и замещать новым добавляемым объектом. При поиске, помимо равенства ключей, мы смотрим, удалён ли элемент, если да, то идём дальше. | ||
| + | |||
===Вставка=== | ===Вставка=== | ||
<pre>insert(item){ | <pre>insert(item){ | ||
| Строка 68: | Строка 83: | ||
return | return | ||
} | } | ||
| − | x = (x + y) | + | x = (x + y) mod m |
} | } | ||
error() //ошибка, требуется увеличить размер таблицы | error() //ошибка, требуется увеличить размер таблицы | ||
| Строка 83: | Строка 98: | ||
else | else | ||
return null | return null | ||
| − | x = (x + y) | + | x = (x + y) mod m |
} | } | ||
return null | return null | ||
| Строка 98: | Строка 113: | ||
else | else | ||
return | return | ||
| − | x = (x + y) | + | x = (x + y) mod m |
} | } | ||
}</pre> | }</pre> | ||
Версия 21:30, 5 мая 2012
Двойное хеширование – метод борьбы с возникающими коллизиями при закрытом хешировании, в котором хеш-таблица заполняется равномерней чем при линейном разрешении коллизий коллизий, что способствует уменьшению размеров кластеров.
Содержание
Принцип двойного хеширования
При двойном хешировании используются две независимые хеш-функции и . Пускай это наш ключ, размер нашей таблицы, это остаток от деления на , тогда сначала исследуется ячейка с адресом , если она уже занята рассматривается , затем и т.д. В общем случае идёт проверка последовательности ячеек где
Выбор хеш-функций
может быть обычной хеш-функцией. Однако что бы в случаях коллизий была проверенна вся хеш-таблица, должна возвращать значения:
- не равные
- независимые от
- взаимно простые с величиной хеш-таблицы
Например, если размер таблицы равен , то в качестве можно использовать функцию вида
Пример
Показана хеш-таблица размером 13 ячеек, в которой используются вспомогательные функции:
Мы хотим вставить ключ 14. Изначально . Тогда . Но ячейка с индексом 1 занята, поэтому увеличиваем на 1 и пересчитываем значение хеш-функции. Делаем так, пока не дойдем до пустой ячейки. При получаем . Ячейка с номером 9 свободна, значит записываем туда наш ключ.
Для того, чтобы последовательность исследования могла охватить всю таблицу, значение должно быть взаимно простым с размером таблицы. Есть два удобных способа это сделать. Первый состоит в том, что в качестве размера таблицы используется простое число, а возвращает натуральные числа, меньшие . Второй - размер таблицы является степенью двойки, а возвращает нечетные значения.
Таким образом, основная особенность двойного хеширования состоит в том, что при различных пара дает различные последовательности ячеек для исследования.
Простая реализация
Пускай у нас есть некоторый объект , в котором определено поле , от которого можно вычислить хеш-функции и
Так же у нас есть таблица величиной состоящая из объектов типа .
Вставка
insert(item){
x = h1(item.key)
y = h2(item.key)
for (i = 0; i < m; i++){
if (table[x] == null){
table[x] = item
return
}
x = (x + y) mod m
}
error() //ошибка, требуется увеличить размер таблицы
}
Поиск
search(key){
x = h1(key)
y = h2(key)
for (i = 0; i < m; i++){
if (table[x] != null)
if (table[x].key == key)
return table[x]
else
return null
x = (x + y) mod m
}
return null
}
Реализация с удалением
Что бы наша хеш-таблица поддерживала удаление, требуется добавить массив типов , равный по величине массиву . Теперь при удалении мы просто будем помечать наш объект как удалённый, а при добавлении как не удалённый и замещать новым добавляемым объектом. При поиске, помимо равенства ключей, мы смотрим, удалён ли элемент, если да, то идём дальше.
Вставка
insert(item){
x = h1(item.key)
y = h2(item.key)
for (i = 0; i < m; i++){
if (table[x] == null || deleted[x]){
table[x] = item
deleted[x] = false
return
}
x = (x + y) mod m
}
error() //ошибка, требуется увеличить размер таблицы
}
Поиск
search(key){
x = h1(key)
y = h2(key)
for (i = 0; i < m; i++){
if (table[x] != null)
if (table[x].key == key && !deleted[x])
return table[x]
else
return null
x = (x + y) mod m
}
return null
}
Удаление
remove(key){
x = h1(key)
y = h2(key)
for (i = 0; i < m; i++){
if (table[x] != null)
if (table[x].key == key)
deleted[x] = true
else
return
x = (x + y) mod m
}
}
См. также
Литература
- Бакнелл Дж. М. Фундаментальные алгоритмы и структуры данных в Delphi, 2003
- Кнут Д. Э. Искусство программирования, том 3. Сортировка и поиск, 2-е издание, 2000
- Томас Кормен, Чарльз Лейзерсон, Рональд Ривест, Клиффорд Штайн. Алгоритмы. Построение и анализ, 2010
- Седжвик Р. Фундаментальные алгоритмы на C. Части 1-4. Анализ. Структуры данных. Сортировка. Поиск, 2003
