- 实现一个优先级队列
- 问题:
- 怎样实现一个按优先级排序的队列?兵器在这个队列上面每次 pop 操作总返回优先级最高的那个元素
- 解决方案:
- 下面利用 heapq 模块实现一个简单的优先级队列:
import heapq
class PriorityQueue(object):
def __init__(self):
self._queue = list()
self._index = 0
def push(self,item,priority):
heapq.heappush(self._queue,(-priority,self._index,item))
self._index += 1
def pop(self):
return heapq.heappop(self._queue)[-1]
class Item(object):
def __init__(self,name):
self.name = name
def __repr__(self):
return "Item({!r})".format(self.name)
q = PriorityQueue()
q.push(Item("foo"),1)
q.push(Item("bar"),5)
q.push(Item("spam"),4)
q.push(Item("grok"),1)
print(q.pop())
print(q.pop())
print(q.pop())
print(q.pop())
- 仔细观察发现,第一个pop()操作返回优先级最高的元素,另外注意到如果连个有着相同优先级的元素 pop操作按照他们被插入到队列的顺序返回的。
- 讨论:这一节我们主要关注 heapq模块的使用。函数 heapq.heappush() 和 heapq.heappop() 分别在队列_queue上插入和删除第一个元素,并且队列_queue保证第一个元素拥有最小的优先级。 heappop()函数总是返回"最小"的元素,这是保证队列pop操作返回正确元素的关键。另外,由于push 和pop操作时间复杂度为0(logN),其中N是堆的大小,因此就算N很大的时候,他们的运行速度也很快。 上面代码中,队列包含了一个(-priority,index,item)的元组。优先级为负数的目的是使元素按照 优先级从高到低排序。这个跟普通的优先级从低到高排序的堆排序恰巧相反。 index变量的作用是保证同优先级元素的正确顺序。通过保存一个不断增加的index下标变量,可以确保 元素按照它们插入的顺序排序。而且,index变量也在相同优先级比较的时候起到重要的作用。
- 为了阐明这些,先假定Item实例是不支持排序的:
a = Item("foo")
b = Item("bar")
print(a < b)
# 上面的程序会报错
- 如果使用元组(priority,item),只要连个元素的优先级不同就能比较。但是两个元组的优先级一样 的话,那么比较操作就会跟之前一样出错:
a = (1,Item("foo"))
b = (5,Item("bar"))
print(a < b) #---> True
c = (1,Item("grok"))
print(a < c)
- 通过引入另外的index变量组成三元组(priority,index,item),就能很好的避免上面的错误,因为 不可能有两个元素有相同的index值。python在做元组比较时,如果前面的比较已经可以确定结果了, 后面的操作就不会发生了:
a = (1, 0, Item("foo"))
b = (5, 1, Item("bar"))
c = (1, 2, Item("grok"))
print(a < b)
print(a < c)
- 如果想在多个线程中使用同一个队列,那么需要增加适当的线程锁和信号量机制。