用Python實現一個優先級隊列(Priority Queue)

堆(Heap)

在實現一個優先隊列以前,先簡單介紹 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 的數據類型還是一個listapi

另外,能夠用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]

優先級隊列(Priority Queue)

優先級隊列的特色:app

  • 給定一個優先級(Priority)
  • 每次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

參考文獻:

  1. Python 3.6 Documentation
  2. Python Cookbook (3rd), O'Reilly.

聲明

原創文章,僅用於我的學習及參考,禁止轉載。一切解釋權歸原做者全部。文中若有錯誤或不足之處請及時指出。指針

相關文章
相關標籤/搜索