Как реализовать приоритетные очереди в 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