Обновление Java PriorityQueue, когда его элементы меняют приоритет

Я пытаюсь использовать PriorityQueue для заказа объектов с помощью Comparator.

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

Есть ли лучший способ, кроме создания класса оболочки вокруг PriorityQueue, чтобы сделать это?

Ответ 1

Вы должны удалить и повторно вставить, поскольку очередь работает, поместив новые элементы в соответствующее положение, когда они вставлены. Это намного быстрее, чем альтернатива поиска элемента с наивысшим приоритетом каждый раз, когда вы выходите из очереди. Недостатком является то, что вы не можете изменить приоритет после того, как элемент был вставлен. У TreeMap есть те же ограничения (как и HashMap, который также ломается, когда хэш-код его элементов изменяется после вставки).

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

Но это будет хуже, и вы хотите синхронизировать в очереди, если вы измените какие-либо приоритеты. Поскольку вам необходимо добавить код синхронизации при обновлении приоритетов, вы можете просто удалить из очереди и поставить в очередь (в обоих случаях вам нужна ссылка на очередь).

Ответ 2

Я не знаю, есть ли реализация Java, но если вы меняете ключевые значения, вы можете использовать кучу Fibonnaci, которая имеет O (1) амортизированную стоимость, чтобы уменьшить значение ключа записи в куча, а не O (log (n)), как в обычной куче.

Ответ 3

Это зависит от того, имеете ли вы прямое управление при изменении значений.

Если вы знаете, когда значения меняются, вы можете удалить или повторно вставить (что на самом деле довольно дорого, так как удаление требует линейного сканирования над кучей!). Кроме того, для этой ситуации вы можете использовать структуру UpdatableHeap (а не на складе java). По сути, это куча, которая отслеживает положение элементов в хэшмапе. Таким образом, когда приоритет элемента изменяется, он может восстановить кучу. В-третьих, вы можете искать кучу Фибоначчи, которая делает то же самое.

В зависимости от скорости обновления каждый раз также может работать линейное сканирование /quicksort/QuickSelect. В частности, если у вас гораздо больше обновлений, чем pull s, это путь. QuickSelect, вероятно, лучше всего, если у вас есть партии обновлений, а затем партии операций pull.

Ответ 4

Чтобы вызвать reheapify, попробуйте это:

if(!priorityQueue.isEmpty()) { priorityQueue.add(priorityQueue.remove()); }

Ответ 5

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

DOWNSIDE: изменяет приоритет для объектов с тем же приоритетом.