Как реализовать приоритетные очереди в Python?

извините за такой глупый вопрос, но документы Python сбивают с толку.. .

Ссылка 1: Реализация Очереди http://docs.python.org/library/queue.html

Он говорит, что очередь имеет contruct для очереди приоритетов. Но я не мог найти как это реализовать.

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? И как его реализовать?

3 ответов


версии очереди модуль реализовала С помощью heapq module, поэтому они имеют равную эффективность для базовых операций кучи.

об этом сказал очереди версия медленнее, потому что она добавляет блокировки, инкапсуляцию и хороший объектно-ориентированный API.

на предложения очереди приоритетов, показанные в документах heapq предназначены для того, чтобы показать, как добавлять дополнительные функции в приоритете очередь (например, стабильность сортировки и возможность изменения приоритета ранее поставленной задачи). Если вам не нужны эти возможности, то basic heappush и heappop функции дадут вам наибольшую производительность.


нет такой вещи, как" наиболее эффективная реализация очереди приоритетов " в любой язык.

приоритетная очередь - это все о компромиссах. См.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_(data_structure)#Comparison_of_theoretic_bounds_for_variants (Как видите,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 реализовать свой собственный, или используйте готовую библиотеку аналогичной кучи, такой как куча спаривания (поиск Google показалhttp://svn.python.org/projects/sandbox/trunk/collections/pairing_heap.py)


если вы заботитесь только о том, какой из двух, на которые вы ссылались, более эффективен (heapq - код на основе http://docs.python.org/library/heapq.html#priority-queue-implementation-notes который вы включили выше, против 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 во-первых, поэтому здесь нельзя сравнивать.)


хотя на этот вопрос был дан ответ и отмечен как принятый, все же здесь простая пользовательская реализация очереди приоритетов без использования какого-либо модуля, чтобы понять, как она работает.

# 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/code/python/algo/priority-queue-in-python.php