簡體   English   中英

如何在STL priority_queue中進行有效的優先級更新?

[英]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個選擇來解決問題,盡管它們都沒有執行真正的更新。

  1. 每次要更新時,請使用priority_queue和push元素。 接受您將在隊列中包含無用條目的事實。 彈出最高值時,檢查它是否包含最新值。 如果沒有,請忽略它並彈出下一個。

    這樣,您可以延遲刪除更新的元素,直到它到達頂部。 我注意到這種方法被頂級程序員用來實現Dijkstra算法。

  2. 使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM