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多进程编程下线程之间变量的共享问题
May 05 Python
Python functools模块学习总结
May 09 Python
django 常用orm操作详解
Sep 13 Python
Python在groupby分组后提取指定位置记录方法
Apr 20 Python
Django如何配置mysql数据库
May 04 Python
对numpy Array [: ,] 的取值方法详解
Jul 02 Python
python通过SSH登陆linux并操作的实现
Oct 10 Python
学python安装的软件总结
Oct 12 Python
python框架Django实战商城项目之工程搭建过程图文详解
Mar 09 Python
如何用Python 实现全连接神经网络(Multi-layer Perceptron)
Oct 15 Python
Python实现查询剪贴板自动匹配信息的思路详解
Jul 09 Python
浅谈Python3中datetime不同时区转换介绍与踩坑
Aug 02 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编程开发“虚拟域名”系统
2006/10/09 PHP
ThinkPHP中的关联模型注意点
2014/06/16 PHP
php实现Session存储到Redis
2015/11/11 PHP
CodeIgniter 完美解决URL含有中文字符串
2016/05/13 PHP
Laravel框架路由管理简单示例
2019/05/07 PHP
php常用字符串查找函数strstr()与strpos()实例分析
2019/06/21 PHP
推荐:极酷右键菜单
2006/11/29 Javascript
jquery刷新页面的实现代码(局部及全页面刷新)
2011/07/11 Javascript
点击页面其它地方隐藏该div的两种思路
2013/11/18 Javascript
通过location.replace禁止浏览器后退防止重复提交
2014/09/04 Javascript
JS实现自动变化的导航菜单效果代码
2015/09/09 Javascript
纯JS实现可拖拽表单的简单实例
2016/09/02 Javascript
jQuery属性选择器用法示例
2016/09/09 Javascript
微信小程序  action-sheet详解及实例代码
2016/11/09 Javascript
canvas实现图片根据滑块放大缩小效果
2017/02/24 Javascript
vue组件watch属性实例讲解
2017/11/07 Javascript
微信小程序switch开关选择器使用详解
2018/01/31 Javascript
解决vue中修改export default中脚本报一大堆错的问题
2018/08/27 Javascript
webpack打包非模块化js的方法
2018/10/24 Javascript
JavaScript基于数组实现的栈与队列操作示例
2018/12/22 Javascript
详解vue 图片上传功能
2019/04/30 Javascript
node 标准输入流和输出流代码实例
2019/09/19 Javascript
[27:08]完美世界DOTA2联赛PWL S2 SZ vs Rebirth 第二场 11.21
2020/11/23 DOTA
python抽象基类用法实例分析
2015/06/04 Python
python3+PyQt5实现自定义分数滑块部件
2018/04/24 Python
python线程池threadpool实现篇
2018/04/27 Python
python 获取毫秒数,计算调用时长的方法
2019/02/20 Python
pyqt 实现QlineEdit 输入密码显示成圆点的方法
2019/06/24 Python
python图形用户接口实例详解
2019/12/16 Python
Python3 hashlib密码散列算法原理详解
2020/03/30 Python
python selenium xpath定位操作
2020/09/01 Python
Nisbets爱尔兰:英国最大的厨房和餐饮设备供应商
2019/01/26 全球购物
2015年教师节贺卡寄语
2015/03/24 职场文书
公司联欢会主持词
2015/07/04 职场文书
PostgreSQL自动更新时间戳实例代码
2021/11/27 PostgreSQL
vue中的可拖拽宽度div的实现示例
2022/04/08 Vue.js