2013-01-19 199 views
4

我試圖實現Prim的算法,並且我需要爲優先級隊列(更新優先級隊列中的鍵值)使用decreaseKey方法。我可以在STL優先級隊列中實現嗎?在STL優先級隊列中實現decreaseKey隊列C++

如果有幫助,這是我下面的算法:每個頂點u在圖G的U至INFINITY

  • SET鍵NIL
  • 的U
  • 集父

  • 將源頂點的密鑰設置爲0
  • 將隊列改爲優先隊列Q使用上述關鍵字在圖中的所有頂點
  • 而Q不空
    • 彈出頂點u與Q中
    • 最低鍵對於每個相鄰的頂點v u的做
      • 如果(v是仍然在Q)和(鍵(U)+權重函數(U,v)<鍵(v)),然後
        • 集合U爲v的父
        • 更新v程序的鍵等於鍵(U)+權重函數(U,v)//這部分給我帶來了問題,因爲我不知道如何在優先級qu中實現reduceKey EUE
+0

我很高興你接受你的答案,有沒有任何理由,你沒有upvote呢? – imslavko

+4

我只有5個聲望,我需要15個upvote所以... – user1641700

回答

8

我不認爲你可以在STL容器實現它。請記住,您始終可以根據矢量編寫自己的堆(優先隊列),但有一項解決方法:

保留您擁有的距離數組,例如d。在你的優先級隊列中你放置了這對距離和這個距離的頂點索引。當您需要從隊列中刪除一些值時,請不要刪除它,只需更新d陣列中的值並將新隊列放入隊列。

每當您從隊列中獲取新值時,請檢查pair中的距離是否確實如此,如在您的數組d中。如果沒有忽略它。

時間是相同的O(MlogM)。內存是O(MlogM),其中M是邊的數量。還有另外一種方法:使用RB-Tree,它可以插入和刪除O(logN)中的鍵並獲得最小值。您可以在std::set容器中的RB-Tree的STL中找到實現。但是,雖然時間複雜度相同,但RB-Tree的工作速度較慢,隱藏常數較大,所以它可能會稍微慢一點,appx。慢了5倍。當然,取決於數據。

+0

謝謝〜示例代碼:http://pastie.org/9097197 – fizzbuzz

+0

該解決方案不是最優的,因爲你將有大量的虛擬數據在你的優先級隊列。首先,你插入N個節點,然後你更新每個節點(在最壞的情況下),所以你最終會在你的隊列中有2 * N個元素。如果N很大,推壓操作會很慢,因爲隨着N變大,log N變大。我認爲最好的解決方案是在隊列中存儲指向元素的指針。以這種方式,你更新一個元素,然後調用make_heap,它取N(常數)爲O(log N)。 –

+0

最初的問題是要求漸近快速的東西,只使用STL。這就是我的答案所提供的。 – imslavko

2

對於另一種方法:比使用std :: set更好。 您可以使用btree :: btree_set(或btree :: safe_btree_set)。 這是一個與谷歌使用B-Tree製作的std :: set相同的實現,與使用RB-Tree的stl不同。這比std :: set和O(logN)好得多。 檢查性能比較: http://code.google.com/p/cpp-btree/wiki/UsageInstructions 而且它也有更低的內存佔用。

+0

好點。我的回答更像是「使用任何平衡的二叉搜索樹」 – imslavko

0

我不是專家,所以希望這不是太愚蠢,但將矢量結合lower_bound工作得很好嗎?

如果您使用lower_bound找到插入新值的正確位置,您的矢量將始終在構建時進行排序,無需排序。當你的向量被排序時,是不是lower_bound具有對數類性能的二進制搜索?

因爲它是排序的,所以找到最小值(或最大值)是一個快照。

要減少密鑰,您需要再次執行lower_bound搜索,刪除操作並再次執行lower_bound操作,以插入縮減密鑰,即= 2對數類操作。還不錯。

或者,您可以更新密鑰並對向量排序。我會猜測隨機訪問,這應該仍然是在對數類,但不知道那裏確實是什麼。

使用排序向量,如果您知道候選關鍵字小於其中的關鍵字,那麼也許您甚至可以對矢量中具有所有較小值的部分進行排序,以獲得更好的性能。

另一個考慮是我認爲sets/maps比vector有更多的內存開銷嗎?

0

我認爲大多數排序僅限於NLogN,所以2個LogN用於重新插入而不是排序可能會更好地用於縮減關鍵操作。

另一件事是插入矢量並不是那麼熱,但總體來說,矢量w lower_bound的想法似乎值得考慮?

謝謝