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

8.4. Приспосабливаемые приоритетные очереди 359

Операционная вставка представлена в Кодовом Фрагменте 8.21. Это по существу

то же самое, как представлено в стандартной приоритетной очереди списка (см. Кодовый Фрагмент 8.9). Так как это объявлено вне класса, мы должны обеспечить полный шаблон specifi-катионы для функции. Мы ищем первый вход p, чье значение ключа превышает наш и вставку e только до этого входа. Мы тогда создаем положение, которое относится к входу только до p, и возвратите его.

шаблон <typename E, typename C> //вставляют элемент typename AdaptPriorityQueue <E, C>:: Положение

AdaptPriorityQueue <E, C>:: вставка (константа E& e)

typename ElementList:: iterator p = L.begin ();

в то время как (p! = L.end () &&! острова (e, *p)) ++ p; L.insert (p, e);

Положение на месте продажи; pos.q =- p;

возвратитесь на месте продажи;

//найдите больший элемент//вставка прежде p

//вставленное положение

Кодовый Фрагмент 8.21: вставка функции для класса AdaptPriorityQueue.

Мы опускаем определения членского размера функций, пустого, минута, и удаляем - Минута, так как они совпадают с в стандартной основанной на списке приоритетной очереди implemen-tation (см. Кодовые Фрагменты 8.8 и 8.10). Затем, в Кодовом Фрагменте 8.22, мы представляем внедрения функций, удаляют и заменяют. Функция удаляет в - полевки стереть функция списка STL, чтобы удалить вход, упомянутый данным положением.

шаблон <typename E, typename C> //удаляют в положении p

недействительный AdaptPriorityQueue <E, C>:: удалите (константа Position& p)

L.erase(p.q);

шаблон <typename E, typename C> //заменяют в положении p typename AdaptPriorityQueue <E, C>:: Положение

AdaptPriorityQueue <E, C>:: замените (константа Position& p, константа E& e)

L.erase(p.q); //удаляют старый вход

возвратите вставку (e); //вставляют замену

Кодовый Фрагмент 8.22: функции удаляют и заменяют для AdaptPriorityQueue.

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

360 Глава 8. Кучи и приоритетные очереди

8.4.2 Осведомленные о местоположении записи

В нашем внедрении приспосабливаемой приоритетной очереди, AdaptPriorityQueue, пред -

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

Отметьте, однако, что этот тот же самый подход потерпел бы неудачу, если бы мы попытались применить его к основанной на куче приоритетной очереди Раздела 8.3.3. Причина состоит в том, что основанное на куче внедрение перемещает записи вокруг кучи (например, посредством пузырения-кучи и пузырения вниз-кучи). Когда элемент e вставлен, мы возвращаем ссылку на вход p содержащий e. Но если e должны были быть перемещены в результате последующих операций, относился к приоритетной очереди, p не изменяется. В результате p мог бы указывать на различный элемент приоритетной очереди. Попытка примениться удаляет (p) или заменяет (p, e ), не относился бы e, но вместо этого к некоторому другому элементу.

Решение этой проблемы включает положения разъединения и записи. В нашем внедрении AdaptPriorityQueue каждое положение p - по существу указатель на узел основной структуры данных (для этого, то, как STL iterator является чеканившим imple-). Если мы перемещаем вход, мы должны также изменить связанный указатель. Чтобы иметь дело с движущимися записями, каждый раз, когда мы вставляем новый элемент e в предшествующее - ity очередь, в дополнение к созданию нового входа в структуре данных, мы также ассигнуем память для объекта, названного локатором. Работа локатора состоит в том, чтобы сохранить настоящее положение p элемента e в структуре данных. Каждый вход приоритетной очереди должен знать свой связанный локатор l. Таким образом, вместо того, чтобы просто хранить сам элемент в приоритетной очереди, мы храним пару (e, &l), состоя из элемента e и указателя на его локатор. Мы называем это осведомленным о локаторе входом. После вставки нового элемента в приоритетной очереди мы возвращаем связанный объект локатора, который указывает этой паре.

Как это решает проблему разъединения? Во-первых, заметьте, что каждый раз, когда пользователь приоритетной очереди хочет определить местонахождение положения p ранее вставленного элемента, это достаточно, чтобы получить доступ к локатору, который хранит это положение. Предположим, однако, что вход двигается в различное положение p в пределах структуры данных. Чтобы обращаться с этим, мы сначала получаем доступ к осведомленному о местоположении входу (e, &l), чтобы получить доступ к локатору l. Мы тогда изменяем l так, чтобы он относился к новому положению p . Пользователь может найти новое положение, получив доступ к локатору.

Цена, которую мы платим за эту дополнительную общность, довольно маленькая. Для каждого входа мы должны к два сохранить два дополнительных указателя (локатор и адрес локатора). Каждый раз, когда мы перемещаем объект в структуру данных, мы должны изменить постоянное число указателей. Поэтому, продолжительность увеличивается просто постоянным множителем.