相信对于队列的概念大家都不会陌生,这种先入先出的数据结构应用很广泛,像一般的生产消费都会用到队列,关于Queue的用法介绍可以参考我之前的文章 python中的Queue与多进程(multiprocessing)还有栈,栈是一种先入后出的数据结构,面优先队列有别于普通的队列与栈,在实现上,它一般通过堆这一数据结构,而堆其实是一种完全二叉树,它会对进入容器的元素进行排序(根据事先指定的规则),出队的顺序则会是二叉树的根结点代表的元素。接下来介绍几种优先队列的实现。

通过heapq模块

heapq是一个二叉堆的实现,它内部使用内置的list对象,它无论插入还是获取最小元素复杂度都在O(log n)。这里主要用到它的heappushheappop方法,heappush 方法需要传入两个参数,一个是列表(list),另外是一个对象,这里的对象须是可比较对象,就是它可以通过cmp方法来比较大小,以下是在 python2 中的代码实现

#coding:gbk
import heapqtasks = []
heapq.heappush(tasks,(10,'aaa'))
heapq.heappush(tasks,(40,'bbb'))
heapq.heappush(tasks,(30,'ccc'))
heapq.heappush(tasks,(20,'ddd'))while tasks:task = heapq.heappop(tasks)print(task)

运行结果如下

(10, 'aaa')
(20, 'ddd')
(30, 'ccc')
(40, 'bbb')

可以看到,我放入 tasks 列表里的元素是个 set 对象,对象第一个元素是个 int 类型的数字,如果使用cmp方法进行比较的话

>>> cmp(10,20)
-1
>>> cmp(10,10)
0
>>> cmp(10,5)
1

对于小于,等于,大于分别返回的是-1,0,1,其实这也是在定义sorted的实现方法,

>>> sorted([(10,'aaaa'),(30,'bbbb')])
[(10, 'aaaa'), (30, 'bbbb')]
>>> sorted([(40,'aaaa'),(30,'bbbb')])
[(30, 'bbbb'), (40, 'aaaa')]
>>> sorted([(30,'aaaa'),(30,'bbbb')])
[(30, 'aaaa'), (30, 'bbbb')]
>>> sorted([(30,'bbbb'),(30,'abbb')])
[(30, 'abbb'), (30, 'bbbb')]

可以看到在sorted方法里,它的排序算法是通过比较第一个元素的大小,小的排在前面,第一个元素相同再比较第二个元素,看返回之前的代码,heapq.heappush 将 set 元素添加到列表元素以后,将对其进行重新排序,将最小的放在前面,于是就得到了上面的打印结果。

上面是使用python自带的 set 数据结构,可否自定义一种类型呢,比较在实现生活中,在上班的第一件事是给自已写一下今天要完成哪些事情,其实哪些事情的优先级比较高就是先做哪些事情,其实在上面也说到 sorted 方法,这个方法其实就是在调用对象的 __cmp__ 方法,好么我可以单独定义一个带有 __cmp__ 方法的对象则可以实现优先队列中的对象排序。

#coding:gbk
import heapq# 使用heapq实现优先队列
#定义一个可比较对象
class CompareAble:def __init__(self,priority,jobname):self.priority = priorityself.jobname = jobnamedef __cmp__(self, other):if self.priority < other.priority:return -1elif self.priority == other.priority:return 0else:return 1joblist = []heapq.heappush(joblist,CompareAble(80,'eat'))
heapq.heappush(joblist,CompareAble(70,'a write plan2'))
heapq.heappush(joblist,CompareAble(70,'write plan'))
heapq.heappush(joblist,CompareAble(90,'sleep'))
heapq.heappush(joblist,CompareAble(100,'write code'))while joblist:task = heapq.heappop(joblist)print(task.priority,task.jobname)

运行结果:

(70, 'write plan')
(70, 'a write plan2')
(80, 'eat')
(90, 'sleep')
(100, 'write code')

上面的compareAble 类初始化有两个参数,一个是优先级,一个是事情的名字,我这里定义的是优先级数值越小排序越靠前,也可以定义成数值越大越靠前。如果优先级相同,则按照插入顺序来排序。

通过Queue,PriorityQueue类型实现

这个优先级队列内部使用了heapq,不同的是PriorityQueue的操作是同步的,提供锁操作,支持并发的生产者和消费者,而且它的接口更加友好,它继承自Queue,所以好多Queue的方法可以直接使用

#coding:gbk
import heapq
from queue import Queue,PriorityQueue# 使用heapq实现优先队列
#定义一个可比较对象
class CompareAble:def __init__(self,priority,jobname):self.priority = priorityself.jobname = jobnamedef __cmp__(self, other):if self.priority < other.priority:return -1elif self.priority == other.priority:return 0else:return 1pq = PriorityQueue()
pq.put(CompareAble(80,'eat'))
pq.put(CompareAble(70,'a write plan2'))
pq.put(CompareAble(70,'write plan'))
pq.put(CompareAble(90,'sleep'))
pq.put(CompareAble(100,'write code'))while pq.qsize()!= 0:task = pq.get_nowait()print(task.jobname,task.priority)

接下来通过一个生产消费的实例来说明优先队列的使用

有三个生产者和二个消费者,生产者向队列中生产有优先级的任务,消费者也是优先消费高级别的任务

#coding:gbk
from queue import PriorityQueue
import time
import random
import threading# 使用heapq实现优先队列
#定义一个可比较对象
class CompareAble:def __init__(self,priority,jobname):self.priority = priorityself.jobname = jobnamedef __cmp__(self, other):if self.priority < other.priority:return -1elif self.priority == other.priority:return 0else:return 1tasks = [(i, "do task %s"%i) for i in range(10,100,5)]
def produce(pq,lock):while True:lock.acquire()task = tasks[random.randint(0,len(tasks)-1)]print('put %s %s in pq'%(task[0],task[1]))pq.put(CompareAble(task[0],task[1]))time.sleep(1)lock.release()def consumer(pq,lock):while True:lock.acquire()task = pq.get_nowait()if task:print(task.priority, task.jobname)else:time.sleep(1)lock.release()if __name__ == '__main__':task_queue = PriorityQueue()task_lock = threading.Lock()for i in range(3):t = threading.Thread(target=produce,args=(task_queue,task_lock))t.setDaemon(False)t.start()for i in range(2):t = threading.Thread(target=consumer,args=(task_queue,task_lock))t.setDaemon(False)t.start()

运行结果:

put 30 do task 30 in pq
put 20 do task 20 in pq
put 75 do task 75 in pq
(20, 'do task 20')
(30, 'do task 30')
put 20 do task 20 in pq
put 15 do task 15 in pq
put 70 do task 70 in pq
(15, 'do task 15')
(20, 'do task 20')
put 85 do task 85 in pq
put 10 do task 10 in pq
put 30 do task 30 in pq
(10, 'do task 10')
(30, 'do task 30')
put 70 do task 70 in pq
put 10 do task 10 in pq
put 55 do task 55 in pq
(10, 'do task 10')
(55, 'do task 55')
put 20 do task 20 in pq
put 45 do task 45 in pq
put 75 do task 75 in pq
(20, 'do task 20')
(45, 'do task 45')
put 40 do task 40 in pq
put 40 do task 40 in pq
...

可以看出,每次取出来的都是当前队列中 priority 最小的数

python3 中的使用方法

上面的代码无法在python3中运行,主要是因为python3没有cmp方法,运行得到的异常信息是

TypeError: unorderable types: CompareAble() < CompareAble()

就是没有一个cmp 的操作

需要在上面定义一个 __lt__ 方法

#coding:gbk
from queue import PriorityQueue
import time
import random
import threading# 使用heapq实现优先队列
#定义一个可比较对象
class CompareAble:def __init__(self,priority,jobname):self.priority = priorityself.jobname = jobname# def __cmp__(self, other):#     if self.priority < other.priority:#         return -1#     elif self.priority == other.priority:#         return 0#     else:#         return 1def __lt__(self, other):if self.priority <= other.priority:return Falseelse:return Truetasks = [(i, "do task %s"%i) for i in range(10,100,5)]
def produce(pq,lock):while True:lock.acquire()task = tasks[random.randint(0,len(tasks)-1)]print('put %s %s in pq'%(task[0],task[1]))pq.put(CompareAble(task[0],task[1]))lock.release()time.sleep(1)def consumer(pq,lock):while True:lock.acquire()try:if pq.empty():continuetask = pq.get_nowait()if task:print(task.priority, task.jobname)finally:lock.release()time.sleep(1)if __name__ == '__main__':task_queue = PriorityQueue()task_lock = threading.Lock()for i in range(3):t = threading.Thread(target=produce,args=(task_queue,task_lock))t.setDaemon(False)t.start()for i in range(2):t = threading.Thread(target=consumer,args=(task_queue,task_lock))t.setDaemon(False)t.start()

上面的代码我修改了一点对于大小的判断,与之前的是反的,这里 priority 越大则越先返回,上面的代码在 python2 中也可以运行,所有如果为了兼容性可以选择定义使用 __lt__ 方法。

参考文章
用Python实现优先级队列的3种方法
python的优先队列示例

更多文章请点击查看我的个人博客

杨彦星 | 序语程言​www.yangyanxing.com

也欢迎关注我的个人公众账号 序语程言

python 优先队列_python中使用优先队列相关推荐

  1. python 优先队列_python实现最大优先队列 python优先级队列如何最大值优先

    python优先级队列如何最大值优先 啥???????队列默认就有优先级即使告别爱情的时候,也希望你一切都好;小编不再爱你的时候,也许不是小编不爱你,只是,小编已不能再爱你. python3 优先队列 ...

  2. python字符集_PYTHON 中的字符集

    Python中的字符编码是个老生常谈的话题,今天来梳理一下相关知识,希望给其他人些许帮助. Python2的 默认编码 是ASCII,不能识别中文字符,需要显式指定字符编码:Python3的 默认编码 ...

  3. python参数化_Python 中如何实现参数化测试的方法示例

    之前,我曾转过一个单元测试框架系列的文章,里面介绍了 unittest.nose/nose2 与 pytest 这三个最受人欢迎的 Python 测试框架. 本文想针对测试中一种很常见的测试场景,即参 ...

  4. kafka python框架_Python中如何使用Apache Avro——Apache的数据序列化系统

    了解如何创建和使用基于Apache Avro的数据,以实现更好,更有效的传输. 在这篇文章中,我将讨论Apache Avro,这是一种开源数据序列化系统,Spark,Kafka等工具正在使用该工具进行 ...

  5. python标准化_python中标准化

    广告关闭 腾讯云11.11云上盛惠 ,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高返5000元! sdk 3.0 实现了统一化,各个语言版本的 sdk具备使用方法相同.接口调用方 ...

  6. python优先级排序_python中使用优先队列

    相信对于队列的概念大家都不会陌生,这种先入先出的数据结构应用很广泛,像一般的生产消费都会用到队列,关于Queue的用法介绍可以参考我之前的文章 python中的Queue与多进程(multiproce ...

  7. python 优先队列_Python中heapq与优先队列【详细】

    本文始发于个人公众号:TechFlow, 原创不易,求个关注 今天的文章来介绍Python当中一个蛮有用的库--heapq. heapq的全写是heap queue,是堆队列的意思.这里的堆和队列都是 ...

  8. python优先队列_python实现最大优先队列

    本文实例为大家分享了python实现最大优先队列的具体代码,供大家参考,具体内容如下 说明:为了增强可复用性,设计了两个类,Heap类和PriorityQ类,其中PriorityQ类继承Heap类,从 ...

  9. python语音识别_Python中的语音识别-完整的入门指南

    python语音识别 Welcome to The Complete Beginner's Guide to Speech Recognition in Python. 欢迎使用Python语音识别完 ...

最新文章

  1. iOS多设备分辨率适配
  2. CAD计算机辅助设计与BIM的区别,3D建模、CAD和BIM三者之间的差异是什么,有什么区别?...
  3. Dataset之MapillaryVistas:MapillaryVistas数据集的简介、下载、使用方法之详细攻略
  4. Apache http强制转为https页面访问(转)
  5. 解决uni-app官方弹框popup关闭不了问题;/pages/extUI/popup/popup;uni-app弹框popup打开调用事件。unin-app弹框封装;
  6. postgresql 客户端_一款功能强大的数据库客户端:DataGrip
  7. c++如何在两个.cpp文件中使用同一个全局变量
  8. 18年12月英语六级第一套听力单词
  9. ps4 DNS服务器未响应,【网络dns设置教程】ps4网络设置教程 dns
  10. 餐饮行业收银系统源码,C# .NET + MSSQL WPF
  11. 单片机|CC2530实验入门
  12. linux权限不够的简易解决方法
  13. STM32学习心得三十三:FLASH闪存编程原理与实验
  14. android/ios播放器ijkplayer Ubuntu编译(支持HTTPS、ffmpeg高版本)
  15. Metasploit Framework(3)Meterpreter
  16. 【GO MICRO V3】protoc-gen-micro 生成proto代码
  17. python+opencv-12 黑帽和礼帽运算
  18. 2020年3月31日 失眠问题解决之道 ~ 观想法②
  19. oracle查看视图定义语句_oracle视图详解
  20. Python错误集锦:python: can’t open file ‘hello’: [Errno 2] No such file or directory

热门文章

  1. mysql多表成绩查询_MySQL多表数据记录查询(一)
  2. python处理json数据_python处理json格式的数据
  3. c语言实践教程实验题答案,C语言课后实验教程习题答案
  4. mysql用户名锁定_MySQL用户锁定
  5. 工业4.0时代,工业交换机在智能电网建设中有什么作用?
  6. 【渝粤教育】电大中专电商运营实操 (19)作业 题库
  7. 物联网时代会给我们带来怎么样的改变?
  8. android studio ignore 模板,android studio git ignore
  9. 蓝桥杯基础模块6_2:定时器进阶
  10. Linux as4开启telnet,linux as4 虚拟机 上开启 telnet 和ssh 和 ftp 服务