實現一個優先級隊列,每次pop 返回優先級最高的元素

 

demo1app

實現一個按優先級排序的隊列, 而且在這個隊列上面每次 pop 操做老是返回優先級最高的那個元素函數

import heapq class PriorityQueue: def __init__(self): self._queue = [] self._index = 0 def push(self, item, priority): heapq.heappush(self._queue, (-priority, self._index, item)) self._index += 1 def pop(self): return heapq.heappop(self._queue)[-1] x=PriorityQueue() x.push(2,1) print(x.pop())

輸出:spa

2

 

使用:code

>>> class Item: ... def __init__(self, name): ... self.name = name ... def __repr__(self): ... return 'Item({!r})'.format(self.name) ... >>> q = PriorityQueue() >>> q.push(Item('foo'), 1) >>> q.push(Item('bar'), 5) >>> q.push(Item('spam'), 4) >>> q.push(Item('grok'), 1) >>> q.pop() Item('bar') >>> q.pop() Item('spam') >>> q.pop() Item('foo') >>> q.pop() Item('grok') >>>

仔細觀察能夠發現,第一個 pop() 操做返回優先級最高的元素。 另外注意到若是兩個有着相同優先級的元素( foo 和 grok ),pop 操做按照它們被插入到隊列的順序返回的.orm

 

 函數 heapq.heappush() 和 heapq.heappop() 分別在隊列 _queue 上插入和刪除第一個元素, 而且隊列 _queue 保證第一個元素擁有最高優先級( 1.4 節已經討論過這個問題)。 heappop() 函數老是返回」最小的」的元素,這就是保證隊列pop操做返回正確元素的關鍵。 另外,因爲 push 和 pop 操做時間複雜度爲 O(log N),其中 N 是堆的大小,所以就算是 N 很大的時候它們運行速度也依舊很快。blog

在上面代碼中,隊列包含了一個 (-priority, index, item) 的元組。 優先級爲負數的目的是使得元素按照優先級從高到低排序。 這個跟普通的按優先級從低到高排序的堆排序恰巧相反。排序

index 變量的做用是保證同等優先級元素的正確排序。 經過保存一個不斷增長的 index 下標變量,能夠確保元素按照它們插入的順序排序。 並且, index 變量也在相同優先級元素比較的時候起到重要做用。隊列

爲了闡明這些,先假定 Item 實例是不支持排序的:it

>>> a = Item('foo') >>> b = Item('bar') >>> a < b Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unorderable types: Item() < Item() >>>

若是你使用元組 (priority, item) ,只要兩個元素的優先級不一樣就能比較。 可是若是兩個元素優先級同樣的話,那麼比較操做就會跟以前同樣出錯:io

>>> a = (1, Item('foo')) >>> b = (5, Item('bar')) >>> a < b True >>> c = (1, Item('grok')) >>> a < c Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unorderable types: Item() < Item() >>>

經過引入另外的 index 變量組成三元組 (priority, index, item) ,就能很好的避免上面的錯誤, 由於不可能有兩個元素有相同的 index 值。Python 在作元組比較時候,若是前面的比較已經能夠肯定結果了, 後面的比較操做就不會發生了:

class Item: def __init__(self, name): self.name = name def __repr__(self): return 'Item({!r})'.format(self.name) a = (1, 0, Item('foo')) b = (5, 1, Item('bar')) c = (1, 2, Item('grok')) print(a>b) print(a<c)

 輸出

False True
相關文章
相關標籤/搜索