在實現一個優先隊列以前,先簡單介紹 heap(堆)的概念。堆,是對於每個父節點上的值都小於或等於子節點的值的二叉樹。此外,一個堆必須是一個完整的二叉樹,除了最底層其餘每一級必須是被完整填充的。所以,堆的最重要的一個特色就是:首項heap[0]
老是最小的一項。 html
而堆化(heapify)則是將一個二叉樹轉化爲一個堆數據結構的過程。在Python中,咱們能夠用自帶heapq
模塊中的heapify(x)
函數來實現將一個列表 x 轉化爲一個堆。時間複雜度爲線性O(N). 代碼以下:python
>>> import heapq >>> x = [1, 8, 2, 23, 7, -4, 18, 23, 42, 37, 2] >>> heap = list(x) >>> heapq.heapify(heap) >>> heap [-4, 2, 1, 23, 7, 2, 18, 23, 42, 37, 8]
heap 是被"堆化"後的列表,heap[0] = -4
爲最小項。注意:此時heap 的數據類型還是一個list
。api
另外,能夠用heappop()
, heappush()
,heapreplace()
等方法來對一個堆列表進行操做。例如,heappop()
會從堆列表中拿出並返回最小項,而且使堆保持不變(即heap[0]
仍爲最小項)。數據結構
>>> heapq.heappop(heap)
-4
>>> heapq.heappop(heap)
1
>>> heapq.heappop(heap)
2
>>> heap
[2, 7, 8, 23, 42, 37, 18, 23]
優先級隊列的特色:app
pop
操做都會返回一個擁有最高優先級的項代碼以下:函數
import heapq class PriorityQueue(object): def __init__(self): self._queue = [] #建立一個空列表用於存放隊列 self._index = 0 #指針用於記錄push的次序 def push(self, item, priority): """隊列由(priority, index, item)形式的元祖構成""" heapq.heappush(self._queue, (-priority, self._index, item)) self._index += 1 def pop(self): return heapq.heappop(self._queue)[-1] #返回擁有最高優先級的項 class Item(object): def __init__(self, name): self.name = name def __repr__(self): return 'Item: {!r}'.format(self.name) if __name__ == '__main__': q = PriorityQueue() q.push(Item('foo'), 5) q.push(Item('bar'), 1) q.push(Item('spam'), 3) q.push(Item('grok'), 1) for i in range(4): print(q._queue) print(q.pop())
對隊列進行4次pop()
操做,打印結果以下:學習
[(-5, 0, Item: 'foo'), (-1, 1, Item: 'bar'), (-3, 2, Item: 'spam'), (-1, 3, Item: 'grok')] Item: 'foo' [(-3, 2, Item: 'spam'), (-1, 1, Item: 'bar'), (-1, 3, Item: 'grok')] Item: 'spam' [(-1, 1, Item: 'bar'), (-1, 3, Item: 'grok')] Item: 'bar' [(-1, 3, Item: 'grok')] Item: 'grok'
能夠觀察出pop()
是如何返回一個擁有最高優先級的項。對於擁有相同優先級的項(bar和grok),會按照被插入隊列的順序來返回。代碼的核心是利用heapq
模塊,以前已經說過,heapq.heappop()
會返回最小值項,所以須要把 priority 的值變爲負,才能讓隊列將每一項按從最高到最低優先級的順序級來排序。spa
原創文章,僅用於我的學習及參考,禁止轉載。一切解釋權歸原做者全部。文中若有錯誤或不足之處請及時指出。指針