Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Data Structures and Algorithms in C++ 2e (На ру...docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
2.37 Mб
Скачать

382 Глава 9. Хеш-таблицы, карты и списки пропуска

9.2.5 Обращающиеся со столкновением схемы

Главная идея хеш-таблицы состоит в том, чтобы взять множество ведра, A, и функция мешанины,

h, и используют их, чтобы осуществить карту, храня каждый вход (k, v) в «ведре» [h (k)]. Этой простой идее бросают вызов, однако, когда у нас есть два отличных ключа, k1 и k2, такой что h (k1) = h (k2). Существование таких столкновений предотвращает нас от простой вставки нового входа (k, v) непосредственно в ведре [h (k)]. Столкновения также усложняют нашу процедуру выполнения находки (k), помещают (k, v), и стирают (k) операции.

Отдельное формирование цепочки

Простой и эффективный путь к контакту со столкновениями состоит в том, чтобы иметь каждое ведро [я]

сохраните маленькую карту, Ми, осуществил использование списка, как описано в Разделе 9.1.4, считая записи (k, v) таким образом что h (k) = я. Таким образом, каждый отдельный Ми приковывают цепью вместе записи, которые крошат к индексу i в связанном списке. Это правило резолюции столкновения известно как отдельное формирование цепочки. Предположение, что мы инициализируем каждое ведро [я], чтобы быть пустой основанной на списке картой, мы можем легко использовать отдельно приковывающее цепью правило выполнить фундаментальные операции по карте как показано в Кодовом Фрагменте 9.5.

Алгоритм находит (k):

Продукция: положение соответствующего входа карты или конец, если нет никакого ключа

k в карте

возвратитесь [h (k)] .find (k)делегируют находку (k) к основанной на списке карте в [h (k)]

Помещенный алгоритм (k, v):

p¬ [h (k)] .put (k, v)делегируют помещенный в основанную на списке карту в [h (k)]

n¬ n+1

возвратите p

Алгоритм стирает (k):

Продукция: ни один

[h (k)] .erase (k)делегируют стирание к основанной на списке карте в [h (k)]

n¬ n-1

Кодовый Фрагмент 9.5: фундаментальные функции карты ADT, осуществленный с хеш-таблицей, которая использует отдельное формирование цепочки, чтобы решить столкновения среди его n записей.

Для каждой фундаментальной операции по карте, включающей ключ k, отдельно приковывающий цепью подход делегирует обработку этой операции к миниатюрной основанной на списке карте, сохраненной в [h (k)]. Так, помещенный (k, v) просматривает этот список, ища вход с ключом, равным k; если это находит один, это заменяет свою стоимость v, иначе, это помещает (k, v) в конце этого списка. Аналогично, найдите (k), перерывает этот список, пока это не достигает конца или

9.2. Хеш-таблицы 383

считает вход с ключом равным k. И сотрите (k), выполняет подобный поиск, но

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

Рисунок 9.4: хеш-таблица размера 13, снабжая 10 записей ключами целого числа, colli-язычками, решенными отдельным формированием цепочки. Функция сжатия - h (k) = k модник 13. Для простоты мы не показываем ценности, связанные с ключами.

Принимая мы используем хорошую функцию мешанины, чтобы внести n записи в указатель нашей карты во множестве ведра способности N, мы ожидаем, что каждое ведро будет иметь размер n/N. Эта стоимость, названная коэффициентом нагрузки хеш-таблицы (и обозначенный сl), должна быть ограничена маленькой константой, предпочтительно ниже 1. Учитывая хорошую функцию мешанины, ожидаемую продолжительность операций находят, помещают и стирают в карте, осуществленной с мешаниной

стол, который использует эту функцию, является O (n/N ⌉). Таким образом мы можем осуществить эти операции

чтобы бежать в O (1), ожидаемое время обеспечило, n - O (N).

Открытое обращение

У отдельно приковывающего цепью правила есть много хороших свойств, таких как обеспечение простых внедрений операций по карте, но у этого, тем не менее, есть один небольшой disadvan-tage. Это требует, чтобы использование вспомогательной структуры данных - списка - держало записи сталкивающимися ключами. Мы можем обращаться со столкновениями другими способами помимо использования отдельного -

384

Глава 9. Хеш-таблицы, Карты и Списки Пропуска, приковывающие правило цепью, как бы то ни было. В частности если пространство в большом почете (например, если мы пишем программу для маленького переносного устройства), тогда мы можем использовать альтернативный подход всегда хранения каждого входа непосредственно в ведре, самое большее один вход за ведро. Этот подход оставляет свободное место, потому что никакие вспомогательные структуры не используются, но это требует, чтобы немного больше сложности имело дело со столкновениями. Есть несколько vari-муравьев этого подхода, коллективно называемого открыто обращающимися схемами, которые мы обсуждаем затем. Открытое обращение требует, чтобы коэффициент нагрузки был всегда самое большее 1 и что записи сохранены непосредственно в клетках самого множества ведра.

Линейное Исследование и его Варианты

Простой открыто обращающийся метод для обработки столкновения - линейное исследование. В этом методе, если мы пытаемся вставить вход (k, v) в ведро [я], который уже занят (где я = h (k)), тогда мы пробуем затем в [(я + 1) модник Н]. Если [(я + 1) модник Н] также занят, то мы пробуем [(я + 2) модник Н], и так далее, пока мы не находим пустое ведро, которое может принять новый вход. Как только это ведро расположено, мы просто вставляем попытку en-там. Конечно, эта стратегия резолюции столкновения требует, чтобы мы изменили внедрение того, чтобы получать (k, v) операция. В частности чтобы выполнить такой поиск, сопровождаемый или заменой или вставкой, мы должны исследовать последовательный доллар - ets, начинающийся с [h (k)], пока мы или не считаем вход с ключом равным k, или мы находим пустое ведро. (См. рисунок 9.5.) Название «линейное исследование» происходит от факта, что доступ к клетке множества ведра может быть рассмотрен как «исследование».

Рисунок 9.5: вставка в хеш-таблицу, используя линейное исследование, чтобы решить столкновения. Здесь мы используем функцию сжатия h (k) = k модник 11.

Чтобы осуществить стирают (k), мы могли бы, сначала, думать, что должны сделать значительную сумму перемены записей, чтобы заставить его посмотреть, как будто вход с ключом k никогда не вставлялся, который будет очень сложен. Типичный способ обойти эту трудность состоит в том, чтобы заменить удаленный вход специальным «доступным» объектом маркера. С этим специальным маркером, возможно занимающим ведра в нашей хеш-таблице, мы изменяем наш алгоритм поиска для, стирают (k) или находят (k) так, чтобы поиск ключа k перескочил через клетки

9.2. Хеш-таблицы 385

содержание доступного маркера и продолжает исследовать до достижения желаемого

вход или пустое ведро (или возвращающийся назад туда, где мы начали). Кроме того, наш алгоритм для помещенного (k, v) должен помнить доступную клетку, с которой сталкиваются во время поиска k, так как это - действительное место, чтобы поместить новый вход (k, v). Таким образом линейное исследование оставляет свободное место, но это усложняет удаления.

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

Квадратное исследование

Другая открыто обращающаяся стратегия, известная как квадратное исследование, включает многократно попытку ведер [(я + f (j)) модник Н], для j = 0, 1, 2..., где f (j) = j2, до нахождения пустого ведра. Как с линейным исследованием, квадратно исследующая стратегия усложняет операцию по удалению, но это действительно избегает видов группирующихся образцов, которые происходят при линейном исследовании. Тем не менее, это создает свой собственный вид объединения в кластеры, названного вторичным объединением в кластеры, где набор заполненных клеток множества «подпрыгивает» вокруг множества в фиксированном образце. Если N не выбран в качестве начала, то квадратно исследующая стратегия может не найти пустое ведро в, даже если Вы существуете. Фактически, даже если N главный, эта стратегия может не найти пустое место, если множество ведра, по крайней мере, наполовину полно. Мы исследуем причину этого типа объединения в кластеры в осуществлении (Упражнение C-9.9).

Дважды хеширование

Другая открыто обращающаяся стратегия, которая не вызывает объединение в кластеры вида про - duced линейным исследованием или квадратным исследованием, является дважды крошащей стратегией. В этом подходе мы выбираем вторичную функцию мешанины, h , и если h наносит на карту некоторый ключ k к ведру [я] со мной = h (k), который уже занят, тогда мы многократно пробуем

спекулирует [(я + f (j)) модник Н] затем, для j = 1, 2, 3..., где f (j) = j h (k). В этом

схема, вторичной функции мешанины не позволяют оценить к нолю; общее

выбор - h (k) = q- (k ультрасовременный q) для некоторого простого числа q <N. Кроме того, N должен быть

начало. Кроме того, мы должны выбрать вторичную функцию мешанины, которая пытается

минимизируйте объединение в кластеры как можно больше.

Эти открыто обращающиеся схемы оставляют некоторое свободное место по отдельно приковывающему цепью методу, но они не обязательно быстрее. В экспериментальном и анальном теоретическом - yses, метод формирования цепочки или конкурентоспособен или быстрее, чем другие методы, в зависимости от коэффициента нагрузки множества ведра. Так, если место в памяти не мама - jor проблема, обращающийся со столкновением предпочтительный метод, кажется, отдельное формирование цепочки.