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 k-近邻算法实例分享
Jun 11 Python
Python实现读取目录所有文件的文件名并保存到txt文件代码
Nov 22 Python
Python检测网站链接是否已存在
Apr 07 Python
用python实现对比两张图片的不同
Feb 05 Python
对numpy中布尔型数组的处理方法详解
Apr 17 Python
PyQt5每天必学之滑块控件QSlider
Apr 20 Python
python list格式数据excel导出方法
Oct 31 Python
django的ORM操作 删除和编辑实现详解
Jul 24 Python
python 操作hive pyhs2方式
Dec 21 Python
python可迭代对象去重实例
May 15 Python
浅谈对python中if、elif、else的误解
Aug 20 Python
Pygame Draw绘图函数的具体使用
Nov 17 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
PHP递归遍历多维数组实现无限分类的方法
2016/05/06 PHP
PHP常见字符串处理函数用法示例【转换,转义,截取,比较,查找,反转,切割】
2016/12/24 PHP
javascript Keycode对照表
2009/10/24 Javascript
Jquery 快速构建可拖曳的购物车DragDrop
2009/11/30 Javascript
JS延迟加载(setTimeout) JS最后加载
2010/07/15 Javascript
基于jquery的内容循环滚动小模块(仿新浪微博未登录首页滚动微博显示)
2011/03/28 Javascript
基于jQuery的动态增删改查表格信息,可左键/右键提示(原创自Zjmainstay)
2012/07/31 Javascript
jQuery动态设置form表单的enctype值(实现代码)
2013/07/04 Javascript
jquery操作select方法汇总
2015/02/05 Javascript
JS实现让访问者自助选择网页文字颜色的方法
2015/02/24 Javascript
js使用split函数按照多个字符对字符串进行分割的方法
2015/03/20 Javascript
Angular Js文件上传之form-data
2015/08/28 Javascript
不想让浏览器运行javascript脚本的方法
2015/11/20 Javascript
jQuery模拟实现的select点击选择效果【附demo源码下载】
2016/11/09 Javascript
jQuery实现的模拟弹出窗口功能示例
2016/11/24 Javascript
js判断一个字符串是以某个字符串开头的简单实例
2016/12/27 Javascript
Angular.js组件之input mask对input输入进行格式化详解
2017/07/10 Javascript
在element-ui的select下拉框加上滚动加载
2019/04/18 Javascript
[01:13]DOTA2群星解读国服召集令 一起说出回归的理由
2013/07/17 DOTA
Python通过DOM和SAX方式解析XML的应用实例分享
2015/11/16 Python
简单谈谈Python中的反转字符串问题
2016/10/24 Python
老生常谈Python进阶之装饰器
2017/05/11 Python
Sublime开发python程序的示例代码
2018/01/24 Python
Python爬虫框架scrapy实现的文件下载功能示例
2018/08/04 Python
浅谈python 读excel数值为浮点型的问题
2018/12/25 Python
python开发之anaconda以及win7下安装gensim的方法
2019/07/05 Python
Python Threading 线程/互斥锁/死锁/GIL锁
2019/07/21 Python
css3背景_动力节点Java学院整理
2017/07/11 HTML / CSS
HTML5中的新元素介绍
2008/10/17 HTML / CSS
我的applet原先好好的, 一放到web server就会有问题,为什么?
2016/05/10 面试题
怎么样写好简历中的自我评价
2013/10/25 职场文书
关于保护环境的标语
2014/06/09 职场文书
企业整改报告范文
2014/11/08 职场文书
大学毕业生个人总结
2015/02/28 职场文书
诚实守信主题班会
2015/08/13 职场文书
68行Python代码实现带难度升级的贪吃蛇
2022/01/18 Python