【数据结构与算法Python版学习笔记】基本数据结构——队列 Queue
定义
-
一系列有序的元素的集合,新元素的加入在队列的一端,这一端叫做“队尾”(rear),已有元素的移除发生在队列的另一端,叫做“队首”(front)。
-
当一个元素被加入到队列之后,它就从队尾开始向队首前进,直到它成为下一个即将被移出队列的元素。
-
“先进先出”(FIFO, first-in first-out)
-
只有一个入口和一个出口
举例
- 排队看电影
- 在杂货店里排队等着付钱
- 在自助餐厅里我们也排队
- 打印
- 计算机科学中队列的例子
- 进程调度
- 键盘缓冲
抽象数据类型Queue
-
Queue()
创建一个空队列对象,无需参数,返回空的队列; -
enqueue(item)
将数据项添加到队尾,无返回值; -
dequeue()
从队首移除数据项,无需参数,返回值为队首数据项; -
isEmpty()
测试是否为空队列,无需参数,返回值为布尔值; -
size()
返回队列中的数据项的个数,无需参数。
enqueue 的复杂度是 O(n),而 dequeue 的复杂度是 O(1)
采用List容纳Queue的数据项
class Queue:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def enqueue(self, item):
return self.items.insert(0, item)
def dequeue(self):
return self.items.pop()
def size(self):
return len(self.items)
应用
热土豆(约瑟夫)问题
算法
- 模拟程序采用队列来存放所有参加游戏的人名,按照传递土豆方向从队首排到队尾
- 模拟游戏开始,只需要将队首的人出队,随即再到队尾入队,算是土豆的一次传递
代码
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()
if __name__ == "__main__":
print(hotPotato(["Bill","David","Susan","Jane","Kent","Brad"],7))
打印任务
建模
- 对象
- 打印任务属性
- 提交时间
- 打印页数
- 打印队列属性
- 具有FIFO性质的打印任务队列
- 打印机属性
- 打印速度
- 是否忙
- 打印任务属性
- 过程
-
生成和提交打印任务
- 确定生产概率
每小时会有10个学生提交20个作业 - 确定打印页数
草稿10页/min,高质量 5页/min
- 确定生产概率
-
实施打印
- 当前的打印作业
- 打印结果倒计时
-
模拟时间
- 统一时间框架
以最小单位(秒)均匀流逝的时间,设定结束时间 - 同步所有过程
在一个时间单位里,对生成打印任务和实施打印两个过程个处理一次
- 统一时间框架
-
模拟流程
- 创建一个打印任务队列。每个任务在生成时被赋予一个“时间邮戳”。队列在开始时是空的。
- 对于每一秒(打印过程中的当前秒(currentSecond):
- 是否有新的打印任务生成?如果有,把它加入打印队列,并把当前秒作为其“时间邮戳”。
- 如果打印机空闲并且有任务正在等待队列中:
- 从打印队列中移除下一个打印任务并且将其提交给打印机;
- 从当前秒中减去“时间邮戳”值,计算得到该任务的等待时间;
- 将该任务的等待时间添加到一个列表中,以用于后续操作;
- 基于打印任务的页数,求出需要多长的打印时间。
- 如果此时打印机在工作中,那对于打印机而言,就工作了一秒钟;对于打印任务而言,它离打印结束又近了一秒钟(剩余打印时间减 1)。
- 如果此时打印任务已经完成,也即是剩余打印时间为 0 时,打印机就进入空闲状态。
- 在整个模拟算法完成后,依据生成的等待时间列表中的数据,计算平均打印时间。
代码
import random
class Printer():
"""打印机类"""
def __init__(self,ppm):
self.pagerate=ppm # 打印速度
self.currentTask=None # 打印任务
self.timeRemaining=0
def tick(self):
"""打印1秒"""
if self.currentTask!=None:
self.timeRemaining-=1
if self.timeRemaining<=0:
self.currentTask=None
def busy(self):
"""打印机是否忙"""
if self.currentTask!=None:
return True
else:
return False
def startNext(self,newtask):
"""打印新作业"""
self.currentTask=newtask
self.timeRemaining=newtask.getPages()*60/self.pagerate
class Task():
"""作业类"""
def __init__(self,time):
self.timestamp=time # 记录生成时间戳
self.pages= random.randrange(1,21) # 随机生成打印页数
def getStamp(self):
return self.timestamp
def getPages(self):
return self.pages
def waitTime(self,currenttime):
return currenttime-self.timestamp
def newPrintTask():
"""1/180 概率生成作业"""
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.startNext(nexttask)
labprinter.tick()
averageWait=sum(waitingtimes)/len(waitingtimes)
print("Average Wait %6.2f secs %3d tasks remaining" % (averageWait,printQueue.size()))
if __name__ == "__main__":
print("-------------ppm=5-----------")
for i in range(10):
simulation(3600,5)
print()
print("-------------ppm=10-----------")
for i in range(10):
simulation(3600,10)
>>>
-------------ppm=5-----------
Average Wait 107.60 secs 0 tasks remaining
Average Wait 101.47 secs 3 tasks remaining
Average Wait 72.62 secs 0 tasks remaining
Average Wait 100.61 secs 3 tasks remaining
Average Wait 115.65 secs 0 tasks remaining
Average Wait 144.67 secs 0 tasks remaining
Average Wait 36.50 secs 0 tasks remaining
Average Wait 125.72 secs 5 tasks remaining
Average Wait 62.21 secs 0 tasks remaining
Average Wait 15.42 secs 0 tasks remaining
-------------ppm=10-----------
Average Wait 7.29 secs 0 tasks remaining
Average Wait 29.45 secs 0 tasks remaining
Average Wait 26.29 secs 0 tasks remaining
Average Wait 18.06 secs 1 tasks remaining
Average Wait 27.65 secs 0 tasks remaining
Average Wait 7.94 secs 0 tasks remaining
Average Wait 7.25 secs 0 tasks remaining
Average Wait 39.70 secs 0 tasks remaining
Average Wait 31.45 secs 0 tasks remaining
Average Wait 22.76 secs 0 tasks remaining
讨论
- 为了对打印模式设置进行决策,我们用模拟程序来评估任务等待时间
- 模拟系统对现实的仿真
- 不耗费现实资源的情况下(有时真实的实验无法进行),可以以不同设定,反复多次模拟来帮助我们进行决策
作者:砥才人
出处:https://www.cnblogs.com/shiroe
本系列文章为笔者整理原创,只发表在博客园上,欢迎分享本文链接,如需转载,请注明出处!