Python实现一个优先级队列的方法


Posted in Python onJuly 31, 2020

问题

怎样实现一个按优先级排序的队列? 并且在这个队列上面每次 pop 操作总是返回优先级最高的那个元素

解决方案

下面的类利用 heapq 模块实现了一个简单的优先级队列:

import heapq

class PriorityQueue:
 def __init__(self):
  self._queue = []
  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:
...  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)
>>> q.pop()
Item('bar')
>>> q.pop()
Item('spam')
>>> q.pop()
Item('foo')
>>> q.pop()
Item('grok')
>>>

仔细观察可以发现,第一个 pop() 操作返回优先级最高的元素。 另外注意到如果两个有着相同优先级的元素( foogrok ),pop 操作按照它们被插入到队列的顺序返回的。

讨论

这一小节我们主要关注 heapq 模块的使用。 函数 heapq.heappush() heapq.heappop() 分别在队列 _queue 上插入和删除第一个元素, 并且队列 _queue 保证第一个元素拥有最高优先级( 1.4 节已经讨论过这个问题)。 heappop() 函数总是返回”最小的”的元素,这就是保证队列pop操作返回正确元素的关键。 另外,由于 push 和 pop 操作时间复杂度为 O(log N),其中 N 是堆的大小,因此就算是 N 很大的时候它们运行速度也依旧很快。

在上面代码中,队列包含了一个 (-priority, index, item) 的元组。 优先级为负数的目的是使得元素按照优先级从高到低排序。 这个跟普通的按优先级从低到高排序的堆排序恰巧相反。

index 变量的作用是保证同等优先级元素的正确排序。 通过保存一个不断增加的 index 下标变量,可以确保元素按照它们插入的顺序排序。 而且, index 变量也在相同优先级元素比较的时候起到重要作用。

为了阐明这些,先假定 Item 实例是不支持排序的:

>>> a = Item('foo')
>>> b = Item('bar')
>>> a < b
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: Item() < Item()
>>>

如果你使用元组 (priority, item) ,只要两个元素的优先级不同就能比较。 但是如果两个元素优先级一样的话,那么比较操作就会跟之前一样出错:

>>> a = (1, Item('foo'))
>>> b = (5, Item('bar'))
>>> a < b
True
>>> c = (1, Item('grok'))
>>> a < c
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unorderable types: Item() < Item()
>>>

通过引入另外的 index 变量组成三元组 (priority, index, item) ,就能很好的避免上面的错误, 因为不可能有两个元素有相同的 index 值。Python 在做元组比较时候,如果前面的比较已经可以确定结果了, 后面的比较操作就不会发生了:

>>> a = (1, 0, Item('foo'))
>>> b = (5, 1, Item('bar'))
>>> c = (1, 2, Item('grok'))
>>> a < b
True
>>> a < c
True
>>>

如果你想在多个线程中使用同一个队列,那么你需要增加适当的锁和信号量机制。 可以查看 12.3 小节的例子演示是怎样做的。

heapq 模块的官方文档有更详细的例子程序以及对于堆理论及其实现的详细说明。

以上就是Python实现一个优先级队列的方法的详细内容,更多关于Python实现优先级队列的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python正则匹配抓取豆瓣电影链接和评论代码分享
Dec 27 Python
python字符串连接的N种方式总结
Sep 17 Python
python中Pycharm 输出中文或打印中文乱码现象的解决办法
Jun 16 Python
Python(TensorFlow框架)实现手写数字识别系统的方法
May 29 Python
Python命名空间的本质和加载顺序
Dec 17 Python
Python批量生成幻影坦克图片实例代码
Jun 04 Python
如何基于python实现归一化处理
Jan 20 Python
Python实现猜年龄游戏代码实例
Mar 25 Python
使用python爬取抖音app视频的实例代码
Dec 01 Python
Python之多进程与多线程的使用
Feb 23 Python
python抢购软件/插件/脚本附完整源码
Mar 04 Python
使用pandas或numpy处理数据中的空值(np.isnan()/pd.isnull())
May 14 Python
django表单中的按钮获取数据的实例分析
Jul 31 #Python
pycharm中使用request和Pytest进行接口测试的方法
Jul 31 #Python
django创建css文件夹的具体方法
Jul 31 #Python
Selenium之模拟登录铁路12306的示例代码
Jul 31 #Python
python的flask框架难学吗
Jul 31 #Python
使用PyCharm安装pytest及requests的问题
Jul 31 #Python
django和flask哪个值得研究学习
Jul 31 #Python
You might like
APMServ使用说明
2006/10/23 PHP
php面向对象全攻略 (十四) php5接口技术
2009/09/30 PHP
PHP的变量总结 新手推荐
2011/04/18 PHP
初步介绍PHP扩展开发经验分享
2012/09/06 PHP
PHP获取windows登录用户名的方法
2014/06/24 PHP
ThinkPHP表单自动提交验证实例教程
2014/07/18 PHP
PHP文件操作之获取目录下文件与计算相对路径的方法
2016/01/08 PHP
php生成毫秒时间戳的实例讲解
2017/09/22 PHP
学习YUI.Ext 第六天--关于树TreePanel(Part 1)
2007/03/10 Javascript
在多个页面使用同一个HTML片段的代码
2011/03/04 Javascript
javascript笔记 String类replace函数的一些事
2011/09/22 Javascript
如何用jquery控制表格奇偶行及活动行颜色
2014/04/20 Javascript
Javascript正则控制文本框只能输入整数或浮点数
2014/09/02 Javascript
全面解析JavaScript的Backbone.js框架中的Router路由
2016/05/05 Javascript
微信支付 JS API支付接口详解
2016/07/11 Javascript
Angular1.x自定义指令实例详解
2017/03/01 Javascript
详解Vue中添加过渡效果
2017/03/20 Javascript
JavaScript获取URL参数的方法之一
2017/03/24 Javascript
详解Angular.js中$http拦截器的介绍及使用
2017/07/04 Javascript
如何实现一个简易版的vuex持久化工具
2019/09/11 Javascript
nodejs制作小爬虫功能示例
2020/02/24 NodeJs
js实现简单五子棋游戏
2020/05/28 Javascript
[08:08]DOTA2-DPC中国联赛2月28日Recap集锦
2021/03/11 DOTA
Python实现抓取网页并且解析的实例
2014/09/20 Python
深入解析Python中的descriptor描述器的作用及用法
2016/06/27 Python
python url 参数修改方法
2018/12/26 Python
ubuntu 16.04下python版本切换的方法
2019/06/14 Python
django框架模板中定义变量(set variable in django template)的方法分析
2019/06/24 Python
python实现实时视频流播放代码实例
2020/01/11 Python
CSS3利用text-shadow属性实现多种效果的文字样式展现方法
2016/08/25 HTML / CSS
新加坡最受追捧的体验平台:Hapz
2018/01/01 全球购物
英国领先的露营和露营车品牌之一:OLPRO
2019/08/06 全球购物
酒吧副总经理岗位职责
2013/12/10 职场文书
卫校中专生的自我评价
2014/01/15 职场文书
农贸市场管理制度
2014/01/31 职场文书
民族团结先进个人材料
2014/02/05 职场文书