Хэш-таблица: почему удаление затруднено в схеме открытой адресации
Я пытаюсь понять метод открытой адресации. Я ссылаюсь на книгу Т. Х. Кормена по этой теме, в которой говорится, что удаление трудно в открытом обращении. Я полностью застрял в этом абзаце:
удаление из хэш-таблицы с открытым адресом затруднено. Когда мы удаляем ключ из слота
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
на этой странице также есть ссылка на некоторые код. Я считаю, что это имеет точно такую же характеристику производительности, как и вставка.
этот метод удаления лучше, чем часто используемая "метка удалена и иногда перефразирует все", потому что вышеуказанный метод является постоянным временем, а не амортизированным постоянным временем. Если у вас есть хэш - таблица из миллиона элементов, которые вы добавляете и удаляете, в методе "пометить удалено" случайное добавление или удаление займет в миллион раз больше времени, чем до и после него, что не является хорошей характеристикой производительности.