我什麼時候應該使用TreeMap 而不是 PriorityQueue?反之亦然?

无发可说發表於2024-03-25

引子

之前周賽(第 390 場周賽記錄-快手)時遇到一題(題幹描述見下圖,實現程式碼見周賽記錄),需要保持容器元素的動態有序(即隨著插入刪除操作後列表始終是有序的)。嘗試過很多資料結構或方案,如列表儲存然後手動呼叫Arrays.sort()進行排序、使用優先佇列實現大/小根堆的方式,但無一例外全部超時😡...

最後用 TreeMap 資料結構方才成功透過✅。因此引發了對一個問題的思考:TreeMap 和 PriorityQueue雖然都是動態保持容器元素有序的資料結構,可以獲取最大值/最小值,但是差異在哪呢,什麼時候使用其中一個會比使用另外一個更有優勢呢?🤔

正文

去網上一搜,發現並不是只有我有這個疑問,以下是關於 StackOverFlow 的高贊問答貼:

When should I use a TreeMap over a PriorityQueue and vice versa?

Seems they both let you retrieve the minimum, which is what I need for Prim's algorithm, and force me to remove and reinsert a key to update its value. Is there any advantage of using one over the other, not just for this example, but generally speaking?

總結高贊回覆貼內容如下,TreeMap 和 PriorityQueue 區別如下,何時使用哪一個可以據此進行分析:

1️⃣ PriorityQueue 允許重複(即具有相同的優先順序),而 TreeMap 不允許。
2️⃣ PriorityQueue 的複雜度是 O(n)(當它增加其大小時),而 TreeMap 的複雜度是 O(logn)(因為它基於紅黑樹)
3️⃣ PriorityQueue 是基於 Array 的,而 TreeMap 中的節點是相互連線的,因此 PriorityQueue 的 contains 方法將花費 O(n) 時間,而 TreeMap 將花費 O(logn) 時間。

針對引子中的題目來說,在基於普通堆的 PriorityQueue(如 Oracle)中,remove(Object) 和 contains(Object) 是線性 O(N),但對於 TreeSet/Map 來說是 O(log(N))。因此,如果存在大量元素並執行大量刪除(物件)或包含(物件)的情況,那麼 TreeSet/Map 可能會更快。

✨ 由於 PriorityQueue 在維護資料總序方面能力較弱,但在一些特殊情況下具有優勢。 如果要跟蹤 N 陣列中最大的 M 個元素,時間複雜度將是 O(NLogM),空間複雜度將是 O(M)。 但如果在TreeMap中執行,則時間複雜度為 O(NlogN),空間複雜度為 O(N)。 這是非常基本的,但在某些情況下我們必須使用優先順序佇列,例如 M 只是一個像 10 這樣的常數。總的來說,TreeMap 維護所有元素的有序(直觀上來說,構建起來是需要時間的)。而PriorityQueue 僅保證最小值或最大值。 它獲取最值開銷相對較小,但功能更弱。

相關文章