簡體   English   中英

如何在 Python 中實現優先隊列?

[英]How to implement Priority Queues in Python?

抱歉問了這么愚蠢的問題,但 Python 文檔令人困惑......

鏈接 1:隊列實現http://docs.python.org/library/queue.html

它說 Queue 有一個優先級隊列的類。 但我找不到如何實現它。

class Queue.PriorityQueue(maxsize=0)

鏈接 2:堆實現http://docs.python.org/library/heapq.html

這里他們說我們可以使用 heapq 間接實現優先級隊列

pq = []                         # list of entries arranged in a heap
entry_finder = {}               # mapping of tasks to entries
REMOVED = '<removed-task>'      # placeholder for a removed task
counter = itertools.count()     # unique sequence count

def add_task(task, priority=0):
    'Add a new task or update the priority of an existing task'
    if task in entry_finder:
        remove_task(task)
    count = next(counter)
    entry = [priority, count, task]
    entry_finder[task] = entry
    heappush(pq, entry)

def remove_task(task):
    'Mark an existing task as REMOVED.  Raise KeyError if not found.'
    entry = entry_finder.pop(task)
    entry[-1] = REMOVED

def pop_task():
    'Remove and return the lowest priority task. Raise KeyError if empty.'
    while pq:
        priority, count, task = heappop(pq)
        if task is not REMOVED:
            del entry_finder[task]
            return task
    raise KeyError('pop from an empty priority queue'

哪個是 Python 中最有效的優先級隊列實現? 以及如何實施?

任何語言都不存在“最有效的優先級隊列實現”這樣的東西。

優先級隊列就是權衡取舍。 http://en.wikipedia.org/wiki/Priority_queue

您應該根據您打算如何使用它來選擇這兩個之一:

  • O(log(N))插入時間和O(1) findMin+deleteMin 時間,或
  • O(1)插入時間和O(log(N)) findMin+deleteMin 時間

在后一種情況下,您可以選擇使用斐波那契堆實現優先級隊列: http : //en.wikipedia.org/wiki/Heap_ ( heapq (如您所見, heapq基本上是一個二叉樹,必須有O(log(N))插入和 findMin+deleteMin)

如果你在處理具有特殊屬性的數據(比如有界數據),那么你可以實現O(1)插入和O(1) findMin+deleteMin 時間。 您只能對某些類型的數據執行此操作,否則您可能會濫用優先級隊列來違反排序時的O(N log(N))界限。

要以任何語言實現任何隊列,您只需要定義insert(value)extractMin() -> value操作。 這通常只涉及底層堆的最小包裝; 參見http://en.wikipedia.org/wiki/Fibonacci_heap來實現你自己的,或者使用一個像配對堆這樣的類似堆的現成庫(谷歌搜索顯示http://svn.python.org /projects/sandbox/trunk/collections/pairing_heap.py )


如果您只關心您引用的兩個中的哪一個更有效(您在上面包含的http://docs.python.org/library/heapq.html#priority-queue-implementation-notes中的基於heapq的代碼,而不是Queue.PriorityQueue ),然后:

關於Queue.PriorityQueue實際上在做什么,網絡上似乎沒有任何容易找到的討論; 您必須深入了解代碼,該代碼鏈接到幫助文檔: http : //hg.python.org/cpython/file/2.7/Lib/Queue.py

   224     def _put(self, item, heappush=heapq.heappush):
   225         heappush(self.queue, item)
   226 
   227     def _get(self, heappop=heapq.heappop):
   228         return heappop(self.queue)

我們可以看到, Queue.PriorityQueue也使用heapq作為底層機制。 因此它們同樣糟糕(漸近地說)。 Queue.PriorityQueue可能允許並行查詢,所以我敢打賭它可能有一個非常輕微的常數因子更多的開銷。 但是因為您知道底層實現(和漸近行為)必須相同,所以最簡單的方法就是在相同的大型數據集上運行它們。

(請注意Queue.PriorityQueue似乎沒有刪除條目的方法,而heapq有。但是這是一把雙刃劍:好的優先級隊列實現可能允許您刪除 O(1) 或 O( log(N)) 時間,但是如果你使用你提到的remove_task函數,並讓那些僵屍任務在你的隊列中累積,因為你沒有從 min 中提取它們,那么你會看到漸近減速,否則你不會看到.當然,首先你不能用Queue.PriorityQueue來做這個,所以這里不能做比較。)

Queue模塊中的版本是使用heapq模塊實現的,因此它們對於底層堆操作具有相同的效率。

也就是說, Queue版本較慢,因為它添加了鎖、封裝和一個很好的面向對象的 API。

heapq 文檔顯示優先級隊列建議旨在展示如何向優先級隊列添加其他功能(例如排序穩定性和更改先前排隊任務的優先級的能力)。 如果您不需要這些功能,那么基本的heappushheappop函數將為您提供最快的性能。

盡管此問題已得到回答並標記為已接受,但這里仍然是 Priority Queue 的一個簡單自定義實現,無需使用任何模塊來了解其工作原理。

# class for Node with data and priority
class Node:

  def __init__(self, info, priority):
    self.info = info
    self.priority = priority

# class for Priority queue 
class PriorityQueue:

  def __init__(self):
    self.queue = list()
    # if you want you can set a maximum size for the queue

  def insert(self, node):
    # if queue is empty
    if self.size() == 0:
      # add the new node
      self.queue.append(node)
    else:
      # traverse the queue to find the right place for new node
      for x in range(0, self.size()):
        # if the priority of new node is greater
        if node.priority >= self.queue[x].priority:
          # if we have traversed the complete queue
          if x == (self.size()-1):
            # add new node at the end
            self.queue.insert(x+1, node)
          else:
            continue
        else:
          self.queue.insert(x, node)
          return True

  def delete(self):
    # remove the first node from the queue
    return self.queue.pop(0)

  def show(self):
    for x in self.queue:
      print str(x.info)+" - "+str(x.priority)

  def size(self):
    return len(self.queue)

在這里找到完整的代碼和解釋: https : //www.studytonight.com/post/implementing-priority-queue-in-python (更新的 URL)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM