stringtranslate.com

Открытая адресация

Коллизия хешей устранена с помощью линейного зондирования (интервал=1).

Открытая адресация или закрытое хеширование — это метод разрешения коллизий в хеш-таблицах . С помощью этого метода коллизия хеш-таблиц разрешается путем зондирования или поиска по альтернативным позициям в массиве ( последовательность зондирования ) до тех пор, пока не будет найдена целевая запись или неиспользуемый слот массива, что указывает на отсутствие такого ключа в таблице. [1] Известные последовательности зондирования включают в себя:

Линейное зондирование
в котором интервал между зондами фиксирован — часто равен 1.
Квадратичный зонд
в котором интервал между зондами увеличивается квадратично (следовательно, индексы описываются квадратичной функцией).
Двойное хеширование
в котором интервал между проверками фиксирован для каждой записи, но вычисляется другой хэш-функцией.

Основные компромиссы между этими методами заключаются в том, что линейное зондирование имеет лучшую производительность кэша , но наиболее чувствительно к кластеризации , в то время как двойное хеширование имеет плохую производительность кэша, но практически не демонстрирует кластеризации; квадратичное зондирование находится посередине в обеих областях. Двойное хеширование также может потребовать больше вычислений, чем другие формы зондирования.

Некоторые методы открытой адресации, такие как хеширование Hopscotch , хеширование Robin Hood , хеширование last-come-first-served и хеширование cuckoo, перемещают существующие ключи в массиве, чтобы освободить место для нового ключа. Это дает лучшее максимальное время поиска, чем методы, основанные на зондировании. [2] [3] [4] [5] [6]

Критическое влияние на производительность хэш-таблицы с открытой адресацией оказывает фактор загрузки , то есть доля используемых слотов в массиве. По мере того, как фактор загрузки приближается к 100%, количество зондов, которые могут потребоваться для поиска или вставки заданного ключа, резко возрастает. Как только таблица заполняется, алгоритмы зондирования могут даже не завершиться. Даже с хорошими хэш-функциями факторы загрузки обычно ограничены 80%. Плохая хэш-функция может демонстрировать низкую производительность даже при очень низких факторах загрузки, создавая значительную кластеризацию, особенно с простейшим методом линейной адресации. Обычно типичные факторы загрузки с большинством методов открытой адресации составляют 50%, в то время как раздельное связывание обычно может использовать до 100%.

Пример псевдокода

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

запись пара { ключ, значение, занятый флаг (изначально не установлен) } var пара слот[0], слот[1], ..., слот[num_slots - 1]
функция find_slot(ключ) i := hash(key) по модулю num_slots // ищем, пока не найдем ключ или пустой слот.  while (slot[i] занят) and (slot[i].key ≠ key) i := (i + 1) по модулю num_slots вернуть я
функция поиска(ключ) я := find_slot(ключ) если слот[i] занят // ключ есть в таблице  return слот[i].значение else  // ключ отсутствует в таблице  return не найден
функция set(ключ, значение) я := find_slot(ключ) если слот[i] занят // мы нашли наш ключ слот[i].значение := значение вернуться  , если таблица почти заполнена перестроить таблицу большего размера (примечание 1) я := find_slot(ключ) отметить слот[i] как занятый слот[i].ключ := ключ слот[i].значение := значение
примечание 1
Перестроение таблицы требует выделения большего массива и рекурсивного использования операции set для вставки всех элементов старого массива в новый больший массив. Обычно размер массива увеличивают экспоненциально , например, удваивая размер старого массива.
функция удалить(ключ) я := find_slot(ключ) если слот[i] не занят, вернуть  // ключ отсутствует в таблице пометить слот[i] как незанятый j := я петля  (примечание 2) j := (j + 1) по модулю num_slots если слот[j] не занят, выйти из цикла k := hash(slot[j].key) по модулю num_slots // определить, лежит ли k циклически в (i,j]  // i ≤ j: | i..k..j |  // i > j: |.k..j i....| или |....j i..k.|  если i ≤ j если (i < k) и (k ≤ j) продолжить цикл  иначе  если (k ≤ j) или (i < k) продолжить цикл отметить слот[i] как занятый слот[i].ключ := слот[j].ключ слот[i].значение := слот[j].значение пометить слот[j] как незанятый я := j
примечание 2
Для всех записей в кластере не должно быть свободных слотов между их естественной позицией хэша и текущей позицией (иначе поиск прекратится до нахождения записи). В этой точке псевдокода i является свободным слотом, который может сделать это свойство недействительным для последующих записей в кластере. j является такой последующей записью. k является необработанным хешем, в котором запись в j естественным образом оказалась бы в хэш-таблице, если бы не было никаких коллизий. Этот тест спрашивает, является ли запись в j недействительной по отношению к требуемым свойствам кластера теперь, когда i является свободным.

Другой метод удаления — просто пометить слот как удаленный. Однако это в конечном итоге требует перестроения таблицы просто для удаления удаленных записей. Методы выше обеспечивают обновление и удаление существующих записей O (1) с периодическим перестроением, если высшая точка размера таблицы растет.

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

Смотрите также

Ссылки

  1. ^ Тененбаум, Аарон М.; Лангсам, Едидия; Огенштейн, Моше Дж. (1990), Структуры данных с использованием C , Prentice Hall, стр. 456–461, стр. 472, ISBN 0-13-199746-7
  2. ^ Поблете; Виола; Манро. «Анализ схемы хеширования с помощью диагонального преобразования Пуассона». стр. 95 книги Яна ван Леувена (ред.) «Алгоритмы — ESA '94». 1994.
  3. ^ Стив Хеллер. «Эффективное программирование на C/C++: меньше, быстрее, лучше» 2014. стр. 33.
  4. ^ Патрисио В. Поблете, Альфредо Виола. «Хеширование Робин Гуда действительно имеет постоянную среднюю стоимость поиска и дисперсию в полных таблицах». 2016.
  5. ^ Пол Э. Блэк, «Хеширование по принципу «последним пришел — первым обслужен»», в Словаре алгоритмов и структур данных [онлайн], под ред. Вреды Питерс и Пола Э. Блэка, 17 сентября 2015 г.
  6. ^ Пол Э. Блэк, «Хеширование Робин Гуда», в Словаре алгоритмов и структур данных [онлайн], Вреда Питерс и Пол Э. Блэк, ред. 17 сентября 2015 г.