[LeetCode] 由 “打印机任务队列" 所想
一、这是个基础问题
Ref: Python之队列模拟算法(打印机问题)【首先研究这个问题作为开始】
任务队列
定义一个任务队列,来管理任务,而无需关心队列的”任务类型"。
# 自定义队列类
class Queue(object):
def __init__(self): #初始化空队列
self.items = [] def isEmpty(self): #是否为空
return self.items == [] def enqueue(self, item): #入队,索引为0,即队尾在左侧
self.items.insert(0,item) def dequeue(self): #出队,列表最后一个,即队首在右侧
return self.items.pop() def size(self): #查看队列的大小
return len(self.items)
遍历循环队列
index不变,elem变化
queue.enqueue(queue.dequeue)
index变化,elem不变
position = index % Queue.size()
打印机类
三个状态:(1)接到一个新任务,就一个key: task timeRemaining(2)忙么?(3)执行任务一秒钟,更新任务状态。
所以,打印机类的”执行任务“,外层是一个”秒针滴答”的循环。
# 打印机类 需要实时监测是否正在执行打印任务
class Printer(object):
def __init__(self, ppm):
self.pagerate = ppm # 页面打印速率:打印一张需要多少秒
self.currentTask = None # 初始化当前任务
self.timeRemaining = 0 # 初始化剩余时间 # 计算正在执行的打印任务的剩余时长,即减去当前秒(1秒时长)后的时长
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 startNext(self, newtask):
self.currentTask = newtask
self.timeRemaining = newtask.getPages() * 60/self.pagerate # 新任务需要的时间秒数: (有几张 * 一张需要多少秒)
任务类
创建一个 “随机大小“ 的任务;并设定好 “生日”。
类中的只读属性,可以考虑使用@property。
# 一个单独的打印任务
class Task(object):
def __init__(self,time):
self.timestamp = time # 出生时间:任务被创建和被放入打印队列时的时间节点
self.pages = random.randrange(1,21) # 随机大小:随机生成1-20页的单个任务的打印页数 # 对外接口:获取时间节点,此处没用到。
def getStamp(self):
return self.timestamp # 对外接口:获取页数
def getPages(self):
return self.pages # 已经等待了多久;用于检索任务开始打印前在队列中的等待时长
def waitTime(self, currenttime):
return currenttime - self.timestamp
开始模拟
例如:评估下”一小时内“ 使用一台 “每分钟打印五张” 打印机的情况,进行模拟。
每一秒,要考虑两个事情:(1)有新任务?(2)能处理新任务?(3)打印机处理一次。
# 指定时长、指定打印速率下的打印函数
def simulation(numSeconds, pagesPerMinute):
labprinter = Printer(pagesPerMinute) # 实例化打印机类,参数为页/分钟
printQueue = Queue() # 创建打印队列
waitingtimes = [] # 初始化等待时长列表 # 模拟:时间是 一秒一秒 地流逝,每一秒都要考虑两个事情。
for currentSecond in range(numSeconds): #在指定时长numSeconds内的当前秒时
# (a) 有新来的打印任务嚒?
if newPrintTask(): #若有打印任务,则
task = Task(currentSecond) #创建打印任务,并记录当前时间节点
printQueue.enqueue(task) #将该打印任务入队
# (b) 若打印机不忙碌,且打印队列不为空,则
if (not labprinter.busy()) and (not printQueue.isEmpty()):
nexttask = printQueue.dequeue() #出队
waitingtimes.append(nexttask.waitTime(currentSecond)) #将该任务等待时长加入等待列表
labprinter.startNext(nexttask) #打印该任务 # (c) 打印机执行一次
labprinter.tick() #计算正在执行的打印任务的剩余时长,并在一次任务结束后将打印机设为空闲 averageWait = sum(waitingtimes) / len(waitingtimes) #平均等待时长
print("Average Wait %6.2f secs %3d tasks remaining." % (averageWait, printQueue.size()))
随机任务
条件判断之模拟,1/180的概率去做一件事。
# 使用随机函数创建打印任务
def newPrintTask():
num = random.randrange(1, 181) #生成随机数,平均3分钟有一个任务
if num == 180:
return True #有打印任务
else:
return False #没有打印任务
程序测试
if __name__ == '__main__':
for i in range(10): #获取10次打印情况
simulation(3600, 5) #获取1小时内,每分钟打印5张的打印情况
Output:
Average Wait 58.35 secs 0 tasks remaining.
Average Wait 85.43 secs 0 tasks remaining.
Average Wait 83.68 secs 4 tasks remaining.
Average Wait 107.12 secs 0 tasks remaining.
Average Wait 71.05 secs 0 tasks remaining.
Average Wait 30.77 secs 3 tasks remaining.
Average Wait 143.09 secs 0 tasks remaining.
Average Wait 195.75 secs 4 tasks remaining.
Average Wait 265.95 secs 1 tasks remaining.
Average Wait 70.94 secs 0 tasks remaining.
二、基础总结
首先,这是一个 “模拟现实” 并做出评估的问题,思维模式具有一定的实际意义。
Input 端的两个随机特性;
- 随机输入
- 随机负载
代码样例如下:
for currentSecond in range(numSeconds):
if random.randrange(0, 180) == 180 # 随机输入
task = Task(currentSecond) # 随机负载
printQueue.enqueue(task)
class Task(object):
def __init__(self,time):
self.timestamp = time
self.pages = random.randrange(1,21) # 随机负载
End.
[LeetCode] 由 “打印机任务队列" 所想的更多相关文章
- [LeetCode] 由 “找零钱" 所想
Ref: [Optimization] Dynamic programming[寻找子问题] Ref: [Optimization] Advanced Dynamic programming[优于re ...
- [Code] 变态之人键合一
目的也比较单纯,选一门语言,走向人键合一. 选了两本书作为操练场:<精通Python设计模式>.<Data Structure and Algorithm in Python> ...
- 装逼名词 bottom-half,软中断,preemptive选项
bottom-half http://bbs.csdn.net/topics/60226240 在中断,异常和系统调用里看Linux中断服务一般都是在关闭中断的情况下执行的,以避免嵌套而是控制复杂化L ...
- WPF打印票据
最近工作的内容是有关于WPF的,整体开发没有什么难度,主要是在打印上因为没有任何经验,犯了一些难,不过还好,解决起来也不是很费劲. WPF打印票据或者是打印普通纸张区别不大,只是说打印票据要把需要打的 ...
- 《转》高级Unix命令
原文链接:http://coolshell.cn/articles/1044.html 在Unix操作中有太多太多的命令,这些命令的强大之处就是一个命令只干一件事,并把这件事干好.Do one thi ...
- 一些不太常用的Linux命令
ACCTCOM 查看所有用户执行过的进程 acctcom | tail - 查看指定用户执行过的进程/命令 acctcom -u <username> | tail - 使用一个正则表达式 ...
- Python 实现队列
操作 Queue() 创建一个空的队列 enqueue(item) 往队列中添加一个item元素 dequeue() 从队列头部删除一个元素 is_empty() 判断一个队列是否为空 size() ...
- 高级Unix命令
在Unix操作中有太多太多的命令,这些命令的强大之处就是一个命令只干一件事,并把这件事干好.Do one thing, do it well.这是unix的哲学.而且Unix首创的管道可以把这些命令任 ...
- 数据结构之队列(Queue)
1,队列的定义 队列:是一种先进先出的数据结构,如下图所示,现进去的数据在队列前面(front),先出队列,后进入队列的数据在后面(rear),后出队列. 队列常用操作: q=Queue() #创建队 ...
随机推荐
- 使用MTA HTML5统计API来分析数据
使用MTA HTML5统计API来分析数据 在开发个人博客的时候,用到了腾讯移动分析(MTA),相比其他数据统计平台来说我喜欢她的简洁高效,易上手,同时文档也比较全面,提供了数据接口供用户调用. 在看 ...
- Luogu P1462 && P1951
首先有两个最短路,可以考虑把一个东西拿出来二分,也就是可以二分最小值,但是注意不要用SPFA他死了,可以用Dij跑最短路,再二分,效率会大大提高 1.SPFA #include<bits/std ...
- AVL树(二叉平衡树)详解与实现
AVL树概念 前面学习二叉查找树和二叉树的各种遍历,但是其查找效率不稳定(斜树),而二叉平衡树的用途更多.查找相比稳定很多.(欢迎关注数据结构专栏) AVL树是带有平衡条件的二叉查找树.这个平衡条件必 ...
- 分布式CAP理论
分布式CAP理论 来自wiki: 在理论计算机科学中,CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer's theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下 ...
- vector function trmplate
/* vector function template programmer:qpz */ #include <iostream> #include <vector> #def ...
- js获取(包括中文)字符串长度与截取字符串
/** * @param begin 截取开始的索引 * @param num 截取的长度 */ //截取字符串(包括中文) function SetString(str, len) { var st ...
- Python 03 整型、字符串
1. 整型和布尔值 1.1 整型——数字(int) 用于比较和运算. 整型32位:-2**31 ~ -2**31-1 整型64位:-2**63 ~ -2**63-1 python2 :整型 int ...
- 一块钱哪里去了?--java浮点型背后的故事
有这样一道智力题:三人住旅馆,老板娘说30元她们付钱后进去了,老板娘想起今天是特价25元,就叫伙计拿5元还给三位顾客,可伙计藏了2元,给了她们3元,这样她们每人得1元,就是说每人付了9元,那3*9=2 ...
- Interger等包装类的比较
Integer a = 1; integer b = 1; integer c = 500; integer d=500; System.out.print(a==b); System.out.pri ...
- 使用SVN钩子强制提交日志和限制提交文件类型
Subversion本身有很好的扩展性,用户可以通过钩子实现一些自定义的功能.所谓钩子实际上是一种事件机制,当系统执行到某个特殊事件时,会触发我们预定义的动作,这样的特殊事件在Subversion里有 ...