Хэш-таблица: почему удаление затруднено в схеме открытой адресации

Я пытаюсь понять метод открытой адресации. Я ссылаюсь на книгу Т. Х. Кормена по этой теме, в которой говорится, что удаление трудно в открытом обращении. Я полностью застрял в этом абзаце:

удаление из хэш-таблицы с открытым адресом затруднено. Когда мы удаляем ключ из слота i, мы не можем просто отметить, что слот пустой на хранение NIL в нем. Это может сделать невозможным получение любого ключа k во время вставки которого мы имели зондированный слот i и обнаружил, что он занят.

Я этого не понимаю. Пожалуйста, объясните это на нескольких примерах.

3 ответов


предположим hash(x) = hash(y) = hash(z) = i. И предположим x был вставлен первым, затем y а то z.
в открытом обращении:table[i] = x, table[i+1] = y, table[i+2] = z.

теперь предположим, что вы хотите удалить x, и установите его обратно в NULL.

когда позже вы будете искать z, вы увидите, что hash(z) = i и table[i] = NULL, и вы вернете неправильный ответ:z нет в таблице.

чтобы преодолеть это, вам нужно установить table[i] С помощью специального маркер, указывающий на функцию поиска, чтобы продолжать смотреть на индекс i+1, потому что там может быть элемент, который его хэш также i.


в схеме открытой адресации поисковые запросы вызывают серию зондов, пока не будет найден ключ или не будет найден пустой слот.

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

стандартное решение заключается в том, чтобы удалить раздел, пометив гнезда, имеющиеся в наличии для resuse-но-не-на самом деле пустой. Иными словами, шагая камень замены добавлен так, что цепи зонда к другим ключам не будут отрезаны коротко.

надеюсь, это поможет вашему пониманию.


удаление из линейной зондируемой открытой адресной хэш-таблицы просто. В течение многих лет на странице хэш-таблицы Википедии был псевдо-код для него. Я не знаю, почему больше нет, но вот Постоянная ссылка назад, когда это было:старая страница хэш-таблицы Википедии, а вот для вашего удобства псевдокод:

function remove(key)
 i := find_slot(key)
 if slot[i] is unoccupied
     return   // key is not in the table
 j := i
 loop
     j := (j+1) modulo num_slots
     if slot[j] is unoccupied
         exit loop
     k := hash(slot[j].key) modulo num_slots
     if (j > i and (k <= i or k > j)) or
        (j < i and (k <= i and k > j)) (note 2)
         slot[i] := slot[j]
         i := j
 mark slot[i] as unoccupied

на этой странице также есть ссылка на некоторые код. Я считаю, что это имеет точно такую же характеристику производительности, как и вставка.

этот метод удаления лучше, чем часто используемая "метка удалена и иногда перефразирует все", потому что вышеуказанный метод является постоянным временем, а не амортизированным постоянным временем. Если у вас есть хэш - таблица из миллиона элементов, которые вы добавляете и удаляете, в методе "пометить удалено" случайное добавление или удаление займет в миллион раз больше времени, чем до и после него, что не является хорошей характеристикой производительности.