我正在尝试学习Python的东西,并且想知道是否有人可以帮助我使用优先级队列的一些示例。我在java中知道它们是如何工作的,但似乎无法看到它们如何在Python中工作的清晰示例。就像我从这里看到队列的大小是.qsize():http://docs.python.org/2/library/queue.html但它没有显示获取最小值,最大值,组织,弹出,添加到队列,排序它们,迭代通过的示例他们。如果有人能给我一个这样的例子,或者指出我在哪里学习这个方向,我真的很感激。
答案 0 :(得分:6)
Queue
不是您要查找的优先级队列。相反,您正在寻找适用于Python list
的{{3}}。您可以使用空列表([]
)或heapify
现有列表,这些列表将会显示:
堆是二叉树,每个父节点的值都小于或等于其任何子节点。此实现使用的数组
heap[k] <= heap[2*k+1]
和heap[k] <= heap[2*k+2]
用于所有k
,从零开始计算元素。
此属性称为堆不变量。您应该注意的一件事是,在这种情况下,排序列表已经作为堆有效(很容易理解为什么 - 因为每个项目都比它的右邻居少,所以必须如此)。堆也是平衡的,保证所有叶节点的高度与根之间的最大差异为1
,这将在后面证明。如果列表未排序,或者尚未排序,则必须调用heapq.heapify
以获取有效堆。
>>> import heapq
>>> L = [2, 3, 1, 9, 10]
>>> heapq.heapify(L)
>>> L
[1, 3, 2, 9, 10]
作为一个堆,现在看起来像
1
/ \
3 2
/ \
9 10
此操作以线性时间(O(N)
时间)工作。如您所见,最小的项始终位于列表的0th
索引处。这使得检索简单:
>>> L[0]
1
最大项目的情况并非如此。在这种情况下,您必须将heapq.nlargest
与n=1
项目一起使用:
>>> heapq.nlargest(1, L)
[10]
要从堆中弹出一个项目,您可以使用heapq.heappop()
,它将从堆中弹出最小的项目。
>>> heapq.heappop(L)
1
执行此操作的代码如下所示:
def heappop(heap):
"""Pop the smallest item off the heap, maintaining the heap invariant."""
lastelt = heap.pop() # raises appropriate IndexError if heap is empty
if heap:
returnitem = heap[0]
heap[0] = lastelt
_siftup(heap, 0)
else:
returnitem = lastelt
return returnitem
这样做会返回0th
元素。但首先它将堆中的最后一项(heap.pop()
将从列表中删除heap[-1]
)与第一项(heap[0] = lastelt
)交换。必须调用_siftup
模块中的隐藏函数heapq
来维护堆不变量。出于科学目的,这里是执行该操作的代码(heapq
使用更快的C
代码实现,但它之前有一个Python实现,在语义上是等效的):
def _siftup(heap, pos):
endpos = len(heap)
startpos = pos
newitem = heap[pos]
# Bubble up the smaller child until hitting a leaf.
childpos = 2*pos + 1 # leftmost child position
while childpos < endpos:
# Set childpos to index of smaller child.
rightpos = childpos + 1
if rightpos < endpos and not cmp_lt(heap[childpos], heap[rightpos]):
childpos = rightpos
# Move the smaller child up.
heap[pos] = heap[childpos]
pos = childpos
childpos = 2*pos + 1
# The leaf at pos is empty now. Put newitem there, and bubble it up
# to its final resting place (by sifting its parents down).
heap[pos] = newitem
_siftdown(heap, startpos, pos)
它基本上与父母一起交换最小的孩子。此操作需要O(log n)
时间,log n
是平衡二叉树的高度。要将项添加到堆使用:
>>> heapq.heappush(L, 7)
>>> L
[3, 7, 10, 9]
花费O(log n)
时间。它首先将项目附加到列表的末尾,因为这会在列表的高度添加一个新节点,比如h
,新节点的索引将等于2*k + 1
或者2*k + 2
,假设(2*k + 1
)某个节点位于索引k
,高度为h - 1
。因此,如果您追加另一个项目,索引将是2*k + 2
,即同一节点的右子项,那么您添加的下一个索引将是最后一个高度{{1}右侧另一个节点的左子节点。这意味着树总是平衡的。如果你最后继续添加,你将填写该行并创建一个新的等等。
无论如何,它调用h - 1
模块中的_siftdown
隐藏函数,如下所示:
heapq
它基本上连续检查孩子是否小于它的父母,如果是,那么它交换两者。由于它是一个平衡的二叉树,树的高度将为def _siftdown(heap, startpos, pos):
newitem = heap[pos]
# Follow the path to the root, moving parents down until finding a place
# newitem fits.
while pos > startpos:
parentpos = (pos - 1) >> 1
parent = heap[parentpos]
if cmp_lt(newitem, parent):
heap[pos] = parent
pos = parentpos
continue
break
heap[pos] = newitem
,O(log n)
是可能需要交换的父项数量,以保持堆不变。
如果要对heapq进行排序,可以使用heapsort在最佳排序时间log n
中进行排序,只需重复调用队列中的O(N log N)
:
heappop
当然,Python的内置[heappop(L) for i in range(len(L))]
比这段代码更优化并且执行速度更快,但如果你不使用Python而只是说在sorted
中实现了堆,你就会这样做。最后迭代堆很容易,只需遍历列表:
C
虽然我认为这不会是任何理想的顺序。
答案 1 :(得分:5)
Queue
模块中的队列主要用于实现多线程的生产者/消费者模式。如果您对通用优先级队列数据结构感兴趣,use the heapq
module。
答案 2 :(得分:-1)
您可以使用PriorityQueue。这是一个例子。
In [1]: from Queue import PriorityQueue
In [2]: pq = PriorityQueue()
In [3]: pq.put((1, "girl")) # put data in the form of tuple (priority, data)
In [4]: pq.put((3, "forest"))
In [5]: pq.put((2, "rain"))
In [6]: pq.get() # retrieves data. lowest priority number first.
Out[6]: (1, 'girl')
In [7]: pq.empty() # checks if empty
Out[7]: False
In [8]: pq.full() # checks if full
Out[8]: False
In [9]: pq.qsize() # current size of the queue.
Out[9]: 2
此外,您还可以扩展PriorityQueue类并自定义内容。