Хеширование кукушки — различия между версиями
Rybak (обсуждение | вклад) м (→См. также) |
Paul1298 (обсуждение | вклад) м |
||
Строка 1: | Строка 1: | ||
[[Image:cuckoo.png|thumb|Пример хеширования кукушки. Стрелки показывают второе возможное место элементов. Если нам надо будет вставить новый элемент на место А, то мы поместим А в его вторую ячейку, занятую В, а В переместим в его вторую ячейку, которая сейчас свободна. А вот помещение нового элемента на место Н не получится: так как Н — часть цикла, добавленный элемент будет вытеснен после прохода по циклу.]] | [[Image:cuckoo.png|thumb|Пример хеширования кукушки. Стрелки показывают второе возможное место элементов. Если нам надо будет вставить новый элемент на место А, то мы поместим А в его вторую ячейку, занятую В, а В переместим в его вторую ячейку, которая сейчас свободна. А вот помещение нового элемента на место Н не получится: так как Н — часть цикла, добавленный элемент будет вытеснен после прохода по циклу.]] | ||
− | '''Хеширование кукушки''' — один из способов борьбы с коллизиями при создании хеш-таблицы. | + | '''Хеширование кукушки'''(англ. ''Cuckoo hashing'') — один из способов борьбы с коллизиями при создании хеш-таблицы. |
==Алгоритм== | ==Алгоритм== | ||
Строка 7: | Строка 7: | ||
Основная идея хеширования кукушки — использование двух хеш-функций вместо одной (далее <tex>h_1(x)</tex> и <tex>h_2(x)</tex>). Также есть вариант алгоритма, в котором используются две хеш-таблицы, и первая хеш-функция указывает на ячейку из первой таблицы, а вторая — из второй. Рассмотрим алгоритмы функций add(x), remove(x) и contains(x). | Основная идея хеширования кукушки — использование двух хеш-функций вместо одной (далее <tex>h_1(x)</tex> и <tex>h_2(x)</tex>). Также есть вариант алгоритма, в котором используются две хеш-таблицы, и первая хеш-функция указывает на ячейку из первой таблицы, а вторая — из второй. Рассмотрим алгоритмы функций add(x), remove(x) и contains(x). | ||
− | Выберем 2 хэш-функции <tex>h_1(x)</tex> и <tex>h_2(x)</tex> (из [[Универсальное семейство хеш-функций | универсального семейства хэш-функций]]). | + | Выберем <tex>2</tex> хэш-функции <tex>h_1(x)</tex> и <tex>h_2(x)</tex> (из [[Универсальное семейство хеш-функций | универсального семейства хэш-функций]]). |
'''Add''' — добавляет элемент с ключом <tex>x</tex> в хэш-таблицу | '''Add''' — добавляет элемент с ключом <tex>x</tex> в хэш-таблицу | ||
Строка 16: | Строка 16: | ||
# Иначе запоминаем элемент из этой ячейки, кладем туда старый. Проверяем, не зациклились ли мы. | # Иначе запоминаем элемент из этой ячейки, кладем туда старый. Проверяем, не зациклились ли мы. | ||
# Если не зациклились, то продолжаем данную процедуру поиска свободного места пока не найдем свободное место или зациклимся. | # Если не зациклились, то продолжаем данную процедуру поиска свободного места пока не найдем свободное место или зациклимся. | ||
− | # Иначе выбираем 2 новые хеш-функции и перехешируем все добавленные элементы. | + | # Иначе выбираем <tex>2</tex> новые хеш-функции и перехешируем все добавленные элементы. |
# Так же после добавления нужно увеличить размер таблицы в случае если она заполнена. | # Так же после добавления нужно увеличить размер таблицы в случае если она заполнена. | ||
Строка 34: | Строка 34: | ||
Зацикливание может возникнуть при добавлении элемента. Пусть мы добавляем элемент <tex>x</tex>. И обе ячейки <tex>h_1(x)</tex> и <tex>h_2(x)</tex> заняты. Пусть, элемент <tex>x</tex> положили в ячейку <tex>h_i(x)</tex>. Если в ходе перемещений элементов в таблице на очередном шаге мы опять хотим переместить элемент <tex>x</tex> в ячейку <tex>h_i(x)</tex>, чтобы в ячейку <tex>h_j(x) ~(i \ne j) </tex> поместить какой-то <tex>y</tex> (это может произойти, если в ходе перемещений элемент <tex>x</tex> был перемещен в ячейку <tex>h_j(x)</tex>), то произошло зацикливание. | Зацикливание может возникнуть при добавлении элемента. Пусть мы добавляем элемент <tex>x</tex>. И обе ячейки <tex>h_1(x)</tex> и <tex>h_2(x)</tex> заняты. Пусть, элемент <tex>x</tex> положили в ячейку <tex>h_i(x)</tex>. Если в ходе перемещений элементов в таблице на очередном шаге мы опять хотим переместить элемент <tex>x</tex> в ячейку <tex>h_i(x)</tex>, чтобы в ячейку <tex>h_j(x) ~(i \ne j) </tex> поместить какой-то <tex>y</tex> (это может произойти, если в ходе перемещений элемент <tex>x</tex> был перемещен в ячейку <tex>h_j(x)</tex>), то произошло зацикливание. | ||
− | Например зацикливание возникнет если добавить в хэш-таблицу 3 элемента <tex>x,y,z</tex> у которых <tex>h_1(x) | + | Например зацикливание возникнет если добавить в хэш-таблицу <tex>3</tex> элемента <tex>x,y,z</tex> у которых <tex>h_1(x)=h_1(y)=h_1(z)</tex> и <tex>h_2(x)=h_2(y)=h_2(z)</tex> . |
==Время работы алгоритма== | ==Время работы алгоритма== | ||
− | Удаление и проверка происходят за <tex>O(1)</tex> (что является основной особенностью данного типа хеширования), добавление в среднем происходит за <tex>O(1)</tex>. Первые два утверждения очевидны: требуется проверить всего лишь 2 ячейки таблицы. | + | Удаление и проверка происходят за <tex>O(1)</tex> (что является основной особенностью данного типа хеширования), добавление в среднем происходит за <tex>O(1)</tex>. Первые два утверждения очевидны: требуется проверить всего лишь <tex>2</tex> ячейки таблицы. |
{{ Утверждение | {{ Утверждение |
Версия 16:35, 21 июня 2017
Хеширование кукушки(англ. Cuckoo hashing) — один из способов борьбы с коллизиями при создании хеш-таблицы.
Алгоритм
Основная идея хеширования кукушки — использование двух хеш-функций вместо одной (далее
и ). Также есть вариант алгоритма, в котором используются две хеш-таблицы, и первая хеш-функция указывает на ячейку из первой таблицы, а вторая — из второй. Рассмотрим алгоритмы функций add(x), remove(x) и contains(x).Выберем универсального семейства хэш-функций).
хэш-функции и (изAdd — добавляет элемент с ключом
в хэш-таблицу- Если одна из ячеек с индексами или свободна, кладем в нее элемент.
- Иначе произвольно выбираем одну из этих ячеек, запоминаем элемент, который там находится, помещаем туда новый.
- Смотрим в ячейку, на которую указывает другая хеш-функция от элемента, который запомнили, если она свободна, помещаем его в нее.
- Иначе запоминаем элемент из этой ячейки, кладем туда старый. Проверяем, не зациклились ли мы.
- Если не зациклились, то продолжаем данную процедуру поиска свободного места пока не найдем свободное место или зациклимся.
- Иначе выбираем новые хеш-функции и перехешируем все добавленные элементы.
- Так же после добавления нужно увеличить размер таблицы в случае если она заполнена.
Remove — удаляет элемент с ключом
из хэш-таблицы.- Смотрим ячейки с индексами и .
- Если в одной из них есть искомый элемент, просто помечаем эту ячейку как свободную.
Contains — проверяет на наличие элемента
в хэш-таблице- Смотрим ячейки с индексами и .
- Если в одной из них есть искомый элемент, возвращаем true.
- Иначе возвращаем false.
Зацикливание
Зацикливание может возникнуть при добавлении элемента. Пусть мы добавляем элемент
. И обе ячейки и заняты. Пусть, элемент положили в ячейку . Если в ходе перемещений элементов в таблице на очередном шаге мы опять хотим переместить элемент в ячейку , чтобы в ячейку поместить какой-то (это может произойти, если в ходе перемещений элемент был перемещен в ячейку ), то произошло зацикливание.Например зацикливание возникнет если добавить в хэш-таблицу
элемента у которых и .Время работы алгоритма
Удаление и проверка происходят за
(что является основной особенностью данного типа хеширования), добавление в среднем происходит за . Первые два утверждения очевидны: требуется проверить всего лишь ячейки таблицы.Утверждение: |
Добавление в среднем происходит за . |
Один из способов доказательства данного утверждения использует теорию случайных графов. Это делается через неориентированный "кукушкин граф", где каждой ячейке хеш-таблицы соответствует ровно одна вершина, а каждому добавленному элементу — ребро с концами в вершинах, соответствующих ячейкам, в которые указывают хеш-функции элемента. При этом элемент будет добавлен без перехеширования тогда и только тогда, когда после добавления нового ребра граф будет оставаться псевдолесом, то есть каждая его компонента связности будет содержать не более одного цикла. |
Таким образом хеширование кукушки является одним из самых быстрых способов хеширования.