Python PriorityQueue —— 优先队列#
Python 默认实现#
Python 默认实现了一个优先级队列,但是它是一个最小堆。这意味着它总是返回最小的元素。
下面的是一个简单的例子:
from queue import PriorityQueue
q3 = PriorityQueue()
q3.put((20, 'code'))
q3.put((100, 'eat'))
q3.put((30, 'sleep'))
print('\nq3\n')
while not q3.empty():
next_item = q3.get()
print(next_item)
如果我们运行上面的代码,我们会得到:
q3
(20, 'code')
(30, 'sleep')
(100, 'eat')
也就是说,不管我们插入的顺序如何,我们总是得到最小的元素。
假如,我们想按照最大的元素来获取,我们可以怎么实现呢?
方法一:通过负数来实现#
该方法实现比较投机取巧,因为 Python 默认的优先队列是最小堆,所以我们可以通过将元素取负数来实现最大堆。
也就是说,在插入元素的时候,我们将元素的值取负数,这样最小的元素就变成了最大的元素。 而在取出元素的时候,我们再将元素的值取负数,这样就恢复了原来的值。
下面的是通过继承 PriorityQueue
来实现的:
1from queue import PriorityQueue
2
3class MaxPriorityQueueV1(PriorityQueue):
4 def _put(self, item):
5 item = (-item[0], item[1])
6 super()._put(item)
7
8 def _get(self):
9 poped = super()._get()
10 return (-poped[0], poped[1])
一个简单的示例代码:
q = MaxPriorityQueueV1()
q.put((2, 'code'))
q.put((1, 'eat'))
q.put((3, 'sleep'))
while not q.empty():
next_item = q.get()
print(next_item)
执行结果为:
(3, 'sleep')
(2, 'code')
(1, 'eat')
方法二:通过 heappush_max
和 _heappop_max
来实现#
如果查看 heapq
模块的源码会发现,它实际上是有 heappush
和 _heappop_max
这两个方法的,
而 heappush_max
并没有实现。
不过,先看一眼 heappush
的实现:
1def heappush(heap, item):
2 """Push item onto heap, maintaining the heap invariant."""
3 heap.append(item)
4 _siftdown(heap, 0, len(heap)-1)
关键的函数是:_siftdown
,同时 heapq
模块中实现了 _siftdown_max
函数。
可以仿照 heappush
实现 heappush_max
:
1def heappush_max(heap, item):
2 """Maxheap variant of heappush."""
3 heap.append(item)
4 _siftdown_max(heap, 0, len(heap)-1)
根据 PriorityQueue
,可以简单的实现 MaxPriorityQueueV2
:
1from queue import Queue
2from heapq import _siftdown_max, _heappop_max
3
4def heappush_max(heap, item):
5 heap.append(item)
6 _siftdown_max(heap, 0, len(heap)-1)
7
8class MaxPriorityQueueV2(Queue):
9 """Variant of Queue that retrieves open entries in priority order (higest first).
10
11 Entries are typically tuples of the form: (priority number, data).
12 """
13
14 def _init(self, maxsize):
15 self.queue = []
16
17 def _qsize(self):
18 return len(self.queue)
19
20 def _put(self, item):
21 heappush_max(self.queue, item)
22
23 def _get(self):
24 return _heappop_max(self.queue)
一个简单的示例代码:
q2 = MaxPriorityQueueV2()
q2.put((20, 'code'))
q2.put((100, 'eat'))
q2.put((30, 'sleep'))
print('\nq2\n')
while not q2.empty():
next_item = q2.get()
print(next_item)
执行结果为:
q2
(100, 'eat')
(30, 'sleep')
(20, 'code')
总结#
对于以上两个实现,暂时没去进行相关的 benchmark,所以不知道哪个更快,占用的内存更少。
下一篇,将对于这两个实现进行 benchmark。