[英]How to do an efficient priority update in STL priority_queue?
我有一個對象的priority_queue:
typedef priority_queue<Object> Queue;
Queue queue;
有時,其中一個對象的優先級可能會發生變化 - 我需要能夠以有效的方式更新隊列中該對象的優先級。 目前我使用的方法雖然有效,但看起來效率低下:
Queue newQueue;
while (!queue.empty())
{
Object obj=queue.top();
queue.pop();
if (priorityHasChanged(obj))
newQueue.push_back(Object(new_priority));
else
newQueue.push_back(obj);
}
newQueue.swap(queue); // this only works because I actually subclassed the priority_queue
// class and exposed a swap method that swaps in the container
我是這樣實現的,因為我當時有點匆忙,這是我能做的最快的事情,我可以確定它能正常工作。 不過必須有比這更好的方法。 真的我想要的是一種方式:
做這個的最好方式是什么?
我可以建議2個選擇來解決問題,盡管它們都沒有執行真正的更新。
每次要更新時,請使用priority_queue
和push元素。 接受您將在隊列中包含無用條目的事實。 彈出最高值時,檢查它是否包含最新值。 如果沒有,請忽略它並彈出下一個。
這樣,您可以延遲刪除更新的元素,直到它到達頂部。 我注意到這種方法被頂級程序員用來實現Dijkstra算法。
使用set
。 它也是排序的,因此您可以在對數時間內提取最大元素。 您還可以在再次插入之前刪除過時的元素。 因此仍然無法進行更新操作,但刪除和重新插入是可行的。
似乎兩種方法的復雜性是相同的。
我認為你對標准優先級隊列運氣不好,因為你無法獲得底層的deque / vector / list或其他什么。 你需要實現自己的 - 它並不難。
使用STL(我知道)執行此操作的最直接方法是刪除條目,更新其優先級,然后重新插入它。 使用std :: priority_queue執行此操作非常慢,但是您可以使用std :: set執行相同的操作。 不幸的是,當它在集合中時,你必須小心不要改變對象的優先級。
我已經實現了一個mutable_priority_queue類,它將std :: multimap(用於優先級到值映射)和std :: map(用於值到優先級映射)粘合在一起,它允許您插入/刪除項目以及以對數方式更新現有值時間。 您可以在此處獲取代碼以及如何使用它的示例
適當的數據結構稱為“Fibonacci Heap”。 但是你需要自己實現它。 插入/更新是O(1)ExtractMin是O(logn)
我已經實現了一個高性能可更新優先級隊列,並使其在github上可用。
這就是您通常使用它的方式:
better_priority_queue::updatable_priority_queue<int,int> pQ;
pQ.push(0, 30); // or pQ.set(0, 30)
pQ.push(1, 20);
pQ.push(2, 10);
pQ.update(2, 25); // or pQ.set(2, 25)
while(!pQ.empty())
std::cout << pQ.pop_value().key << ' ';
// Outputs: 0 2 1
為了補充Jarekczek的答案,如果set
和“無用條目的純堆”方法確實具有相同的復雜性,則stl::set
版本通常比stl::priority_queue
版本執行速度慢得多,因為它是通過實現的紅黑樹只能保證它們的深度低於2 * log_2(n_elements)並且需要定期更新,而stl::priority_queue
是一個盡可能純的快速二進制堆。 這就是它在實現Dijkstra時通常使用的原因。
但是,在少數基節點上進行大量更新時,設置方法可能會更快。 這也是使用我的庫將為您帶來最大改進的地方。
很遺憾,您無法更新priority_queue中的值。 priority_queue不提供此類接口。
我認為你最好使用set
作為Jarekczek說或使用這個解決方案 (使用make_heap)。
你可能想看看replace_if
這里有一個例子。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.