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

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

9.3 Заказанные Карты

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

Когда записи карты сохранены в заказе, мы можем обеспечить эффективный im-plementations для дополнительных функций в карте ADT. Как со стандартной картой ADT, чтобы указать, что объект не присутствует, класс обеспечивает spe-cial страж iterator названный концом. Заказанная карта включает все функции стандартной карты ADT плюс следующее:

firstEntry (k): Возвратите iterator к входу с самым маленьким значением ключа; если

карта пуста, она возвращает конец.

lastEntry (k): Возвратите iterator к входу с самым большим значением ключа; если

карта пуста, она возвращает конец.

ceilingEntry (k): Возвратите iterator к входу с наименьшим количеством значения ключа

больше, чем или равный k; если нет такого входа, это возвращает конец.

floorEntry (k): Возвратите iterator к входу с самым большим значением ключа

меньше чем или равный k; если нет такого входа, это возвращает конец.

lowerEntry (k): Возвратите iterator к входу с самым большим значением ключа

меньше, чем k; если нет такого входа, это возвращает конец.

higherEntry (k): Возвратите iterator к входу с наименьшим количеством значения ключа

больше, чем k; если нет такого входа, это возвращает конец.

Осуществление заказанной карты

Заказанная природа операций, данных выше для заказанной карты ADT, делает

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

9.3. Заказанные карты 395

9.3.1 Заказанные столы поиска и двоичный поиск

Если ключи в карте прибывают из полного заказа, мы можем сохранить записи карты в a

вектор L в увеличивающемся заказе ключей. (См. рисунок 9.6.) Мы определяем, что L - вектор, а не список узла, потому что заказ ключей в векторе L допускает более быстрый поиск, чем, был бы возможен, имел L, скажем, осуществленный со связанным списком. По общему признанию у хеш-таблицы есть хорошая ожидаемая продолжительность для поиска. Но его время худшего случая для поиска не лучше, чем связанный список, и в некоторых заявлениях, таких как в режиме реального времени обработка, мы должны гарантировать худшее - связанный поиск случая. У быстрого алгоритма для поиска в заказанном векторе, который мы обсуждаем в этом подразделе, есть хорошая гарантия худшего случая на ее продолжительности. Таким образом, это могло бы быть предпочтено по хеш-таблице в определенных заявлениях. Мы обращаемся к этому заказанному векторному внедрению карты как заказанный стол поиска.

Рисунок 9.6: Реализация карты посредством заказанного стола поиска. Мы показываем только ключи для этой карты, чтобы выдвинуть на первый план их заказ.

Космическое требование заказанного стола поиска - O (n), который подобен основанному на списке внедрению карты (Раздел 9.1.4), предполагая, что мы выращиваем и сокращаем множество, поддерживающее вектор L, чтобы сохранять размер этого множества пропорциональным числу записей в L. В отличие от незаказанного списка, однако, выполнение обновлений в столе поиска занимает значительное количество времени. В частности выполняя вставку (k, v) операция в столе поиска требует O (n) время в худшем случае, так как мы должны переместить все записи в векторе с ключом, больше, чем k создать место для нового входа (k, v). Подобное наблюдение относится к операции, стирают (k), так как это берет O (n) время в худшем случае, чтобы переместить все записи в векторе с ключом, больше, чем k закрыть «отверстие», оставленное удаленным входом (или записями). Внедрение стола поиска поэтому низшее по сравнению со связанным внедрением списка с точки зрения продолжительности худшего случая операций по обновлению карты. Тем не менее, мы можем выполнить функцию находки намного быстрее в столе поиска.

Двоичный поиск

Значительное преимущество использования заказанного вектора L, чтобы осуществить карту с n

записи состоят в том, что доступ к элементу L его индексом берет O (1) время. Мы вспоминаем от Раздела 6.1, что индекс элемента в векторе - ряд элементов, предшествующий ему. Таким образом у первого элемента в L есть индекс 0, и последний элемент имеет

индекс n - 1. В этом подразделе мы даем классический алгоритм, двоичный поиск, к

определите местонахождение входа в заказанном столе поиска. Мы показываем, как этот метод может использоваться

396

Глава 9. Хеш-таблицы, Карты и Списки Пропуска, чтобы быстро выполнить функцию находки карты ADT, но подобный метод могут использоваться для каждой из функций заказанной карты, ceilingEntry, floorEntry, lowerEntry, и higherEntry.

Элементы, сохраненные в L, являются записями карты, и так как L заказан, en-

попробуйте в индексе, у меня есть ключ, не меньший, чем ключи записей в индексах 0..., я- 1,

и не больше, чем ключи записей в индексах i + 1..., n- 1. Это наблюдение

позволяет нам быстро «домой в» на ключе поиска k использование варианта детского

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

индекс, по крайней мере, низкий и в самом высоком в L. Первоначально, низко = 0 и высоко = n- 1. Мы

тогда сравните k с ключом среднего кандидата e, то есть, вход e с индексом

середина =⌊ (низко + высоко)/2.

Мы рассматриваем три случая:

• Если k = e.key (), то мы нашли вход, который мы искали, и

поиск заканчивает успешно возвращение e

• Если k <e.key (), то мы повторяемся на первой половине вектора, то есть, на

ряд индексов от низко до середины- 1 Этот метод поиска называют двоичным поиском и дают в псевдокодексе в Кодексе • Если k> e.key (), мы повторяемся на ряду индексов от середины + 1 к высоко

Фрагмент 9.18. Операция находит (k) на карте n-входа осуществленный с заказанным вектором L, состоит из запроса BinarySearch (L, k, 0, n- 1). Алгоритм BinarySearch (L, k, низко, высоко):

Вход: заказанный вектор L хранящий n записи и низкий выпуск продукции целых чисел и высокая производительность: вход L с ключом равняется k и индексу между низким и высоким, если

такой вход существует, и иначе специальный конец стража

если низко> высоко тогда

возвратите конец

еще

середина¬⌊ (низко + высоко)/2 ⌋

e¬ L.at (середина)

если k = e.key () тогда

возвратите e

еще, если k <e.key () тогда

возвратите BinarySearch (L, k, низко, середина- 1)

еще

возвратите BinarySearch (L, k, середина + 1, высоко)

Кодовый Фрагмент 9.18: Двоичный поиск в заказанном векторе.