Page cover

heapify(), merge()


此函數在線性時間內將 list x 轉換為 heap。

PYTHON
heapify(x)

List in-place 重新排列,這意味著不使用額外的記憶體。複雜度為 O(n),其中 n 是 x 中的項目數。

當你有一個未排序的 list,但需要按排序順序重複提取元素 (尤其是最小的元素) 時,此函數特別有用。

將多個排序輸入 *iterables,合併為一個排序輸出 (返回 iterator)。

類似於 sorted(itertools.chain(*iterables)),但返回一個 iterable 物件,不會一次將資料全部拉入內存,並假設每個輸入 streams 都已排序 (從小到大)。

在您有多個排序序列 (例如文件或 lists),並且需要將它們有效且按排序順序合併為單個 sequence 的情況下很有用。

PYTHON
merge(*iterables,key=None,reverse=False)
參數
說明

key

指定一個參數的 key function,用於從每個輸入元素中提取比較 key。預設值為 None (直接比較元素)。

reverse

反轉。要實作類似 sorted(itertools.chain(*iterables), reverse=True) 的行為,所有可迭代物件都必須從最大到最小排序。

範例 – Basic Usage


Example: 在未排序的 list 中,尋找 3 個最小的元素。

如果您只需要尋找一次最小或最大元素,請避免使用 heapq.heapify。在這種情況下,min()max() 效率更高。

Example: 合併多個排序 lists。

nlargest(), nsmallest()


iterable 找出 n 個最大元素。

參數
說明

n

要返回的元素數量。

iterable

從中尋找元素的資料。

key

指定一個參數的 key function,用於從每個輸入元素中提取比較 key。預設值為 None (直接比較元素)。

iterable 找出 n 個最小元素。

參數
說明

n

要返回的元素數量。

iterable

從中尋找元素的資料。

key

指定一個參數的 key function,用於從每個輸入元素中提取比較 key。預設值為 None (直接比較元素)。

heapq.nlargestheapq.nsmallest 對於只需要幾個元素的大型資料集特別有效。它們的性能比對整個 list 進行排序,然後對其進行 slicing 要好,尤其是當 n 遠小於輸入的大小時。

範例 – Basic Usage


Example 1: Basic Usage

Example 2: 使用 key function

執行結果:

範例 – Maintained Heap


如果您需要頻繁更新集合並檢索 n 個最大或最小元素,則 Maintained heaps 或 Balanced Binary Search Tree 等資料結構可能會更有效。

在這種情況下,每次使用 heapq.nlargestheapq.nsmallest 可能會效率很低,因為這些函數需要在每次呼叫時,處理整個資料集。

相反,maintaining a heap 或使用 balanced binary search tree (如, AVL Tree, Red-Black Tree) 可能會更有效。這些資料結構允許更快的插入和刪除操作,同時還提供存取最大或最小元素的有效方法。

Example 1: 假設您有一個不斷更新的 stream,並且您需要追蹤 3 個最大的元素。使用 min-heap 可能是有效的。

執行結果:

Balanced Binary Search Tree (BST) 對於動態資料集來說甚至更有效率,因為它維護有序結構,允許快速插入、刪除和檢索。但是,Python 沒有內建的 balanced BST,因此您可以使用 third-party library 或實作一個。

Challenges


排序穩定性和 Tuple 比較問題

  1. 排序穩定性:在優先權佇列中,您希望具有相同優先權的任務按照新增的順序進行處理。這稱為 "sort stability"。

  2. Tuple 比較問題:如果您只是使用像 (priority, task) 這樣的 tuples 作為 queue items。當優先權相等時,Python 將比較元組的兩個元素。如果 task 物件無法相互比較,就會出現問題。

提供的解決方案是使用 3 元素的 list or tuple,即 (priority、entry_count、task)。這就是為什麼它有效的原因:

  • Entry Count:這是每個任務的唯一識別碼 (如時間戳記)。當兩個任務具有相同優先權時,heapq module 將比較它們的條目計數。由於這些都是唯一的,並且對於每個新任務都是遞增的,因此它確保了排序穩定性。

  • Tuple 比較:透過條目計數,Python's tuple 比較不需要直接比較任務,從而避免了不可比較任務的問題。

解決不可比較任務問題的另一個解決方案是建立一個 wrapper class,該 class 忽略 task item 並且僅比較優先順序 field。

執行結果:

當使用 heappop() 擷取項目時,它們會依優先順序遞增的順序返回 (數字越小表示優先順序越高)。每個PrioritizedItem 實例的 item 屬性儲存實際任務,這是不可比較的,但這不會影響佇列操作,因為僅使用 priority 進行比較。

當您的任務無法相互比較,但需要確定優先順序時,此方法特別有用。 dataclasses module 可以方便地建立具有所需比較行為的結構化物件。

更改優先權和刪除任務


  1. 更改優先權:如何處理任務新增到 queue 後,優先權發生變更的情況。

  2. 刪除任務:如何從 queue 中尋找並刪除特定任務,尤其是待處理的任務。

刪除條目或更改其優先順序更加困難,因為這會破壞 heap 結構不變量。因此,一個可能的解決方案是將條目標記為已刪除,並新增具有修改優先順序的新條目:

執行結果:

參考資料


heapq — Heap queue algorithm — Python 3.12.0b4 documentation

Binary Heap Basics. In my last article I outlined the tree… | by Michael Verdi | Medium

Last updated

Was this helpful?