什么是队列?
队列是一种有次序的数据集合,其特征是:
新数据项的添加总发生在一端(通常称为“尾 rear”端)
而现存数据项的移除总发生在另一端(通常称为 “首front”端)
当数据项加入队列,首先出现在队尾,随 着队首数据项的移除,它逐渐接近队首。
这种次序安排的原则称为(FIFO:First-in first-out)先进先出 或“先到先服务first-come first-served”
抽象数据类型Queue
Queue():创建一个空队列对象,返回值为 Queue对象;
enqueue(item):将数据项item添加到队尾, 无返回值;
dequeue():从队首移除数据项,返回值为队首 数据项,队列被修改;
isEmpty():测试是否空队列,返回值为布尔值 size():返回队列中数据项的个数。
Python实现ADT Queue
# Chenyj
class Queue:
def __init__(self):
self.items=[]
def isEmpty(self):
return self.items==[]
def enqueue(self,item):
self.items.insert(0,item)
def dequeue(self):
return self.items.pop()
def size(self):
return len(self.items)
采 用 List 来容纳 Queue的数据项 将List首端作为队列 尾端 List的末端作为队列 首端 enqueue()复杂度为 O(n) dequeue()复杂度为 O(1)
首尾倒过来的实现 ,复杂度也倒过来
队列的应用:热土豆(约瑟夫问题)
传说犹太人反叛罗马人,落到困境,约瑟夫和39 人决定殉难,坐成一圈儿,报数1~7,报到7的 人由旁边杀死,结果约瑟夫给自己安排了个位置 ,最后活了下来……
用队列来实现热土豆问题的算法,参加游 戏的人名列表,以及传土豆次数num,算 法返回最后剩下的人名
模拟程序采用队列来存放所有参加游戏的人名, 按照传递土豆方向从队首排到队尾 游戏时,队首始终是持有土豆的人
模拟游戏开始,只需要将队首的人出队,随即再 到队尾入队,算是土豆的一次传递 传递了num次后,将队首的人移除,不再入队 如此反复,直到队列中剩余1人
热土豆问题:代码
# Chenyj
from pythonds.basic.queue import Queue
def hotPotato(namelist,num):
simqueue=Queue()
for name in namelist:
simqueue.enqueue(name)
while simqueue.size()>1:
for i in range(num):
simqueue.enqueue(simqueue.dequeue())#一次传递
simqueue.dequeue()
return simqueue.dequeue()
print(hotPotato(['Bill','David','Susan','Jane','Kent','Brad'],7))
运行结果: Susan
队列的应用:打印任务
多人共享一台打印机,采取“先到先服务 ”的队列策略来执行打印任务。在这种设定下,一个首要的问题就是: 这种打印作业系统的容量有多大? 在能够接受的等待时间内,系统能容纳多少用户 以多高频率提交多少打印任务?
打印任务问题:模拟流程
创建打印队列对象。时间按照秒的单位流逝 按照概率生成打印作业,加入打印队列 如果打印机空闲,且队列不空,则取出队首作业 打印,记录此作业等待时间 如果打印机忙,则按照打印速度进行1秒打印 如果当前作业打印完成,则打印机进入空闲 。时间用尽,开始统计平均等待时间。
作业的等待时间 生成作业时,记录生成的时间戳 开始打印时,当前时间减去生成时间即可。
作业的打印时间 生成作业时,记录作业的页数 开始打印时,页数除以打印速度即可。
# Chenyj
from pythonds.basic.queue import Queue
import random
class Printer:
def __init__(self,ppm):
self.pagerate=ppm #cyj 打印速度
self.currentTask=None #打印任务
self.timeRemaining=0 #任务倒计时
def tick(self): #打印一秒
if self.currentTask !=None:
self.timeRemaining=self.timeRemaining-1
if self.timeRemaining<=0:
self.currentTask=None
def busy(self): #打印忙?
if self.currentTask!=None:
return True
else:
return False
def starNext(self, newtask): #打印新作业
self.currentTask=newtask
self.timeRemaining=newtask.getPages()*60/self.pagerate
打印任务问题:Python代码2
# Chenyj
import random
class Task:
def __init__(self,time):
self.timestamp=time
self.pages=random.randrange(1,21)
def getStamp(self):
return self.pages
def waitTime(self,currenttime):
return currenttime-self.timestamp
def newPrintTask():
num=random.randrange(1,181)
if num==180:
return True
else:
return False
def simulation(numSeconds,pagesPerMinute):
labprinter=Printer(pagesPerMinute)
printQueue=Queue()
waitingtimes=[]
for currentSecond in range(numSeconds):
if newPrintTask():
task=Task(currentSecond)
printQueue.enqueue(task)
if(not labprinter.busy()) and (not printQueue.isEmpty()):
nexttask =printQueue.dequeue()
waitingtimes.append(nexttask.waitTime(currentSecond))
labprinter.starNext(nexttask)
labprinter.tick()
averageWait=sum(waitingtimes)/len(waitingtimes)
print('Average Wait %6.2f sec %3d tasks remaining'%(averageWait,printQueue.size()))
为了对打印模式设置进行决策,我们用模 拟程序来评估任务等待时间 通过两种情况模拟仿真结果的分析,我们认识到 如果有那么多学生要拿着打印好的程序源代码赶 去上课的话 那么,必须得牺牲打印质量,提高打印速度。
模拟系统对现实的仿真 在不耗费现实资源的情况下——有时候真实的实验 是无法进行的 可以以不同的设定,反复多次模拟 来帮助我们进行决策。