一、这是个基础问题

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] 由 “打印机任务队列" 所想的更多相关文章

  1. [LeetCode] 由 “找零钱" 所想

    Ref: [Optimization] Dynamic programming[寻找子问题] Ref: [Optimization] Advanced Dynamic programming[优于re ...

  2. [Code] 变态之人键合一

    目的也比较单纯,选一门语言,走向人键合一. 选了两本书作为操练场:<精通Python设计模式>.<Data Structure and Algorithm in Python> ...

  3. 装逼名词 bottom-half,软中断,preemptive选项

    bottom-half http://bbs.csdn.net/topics/60226240 在中断,异常和系统调用里看Linux中断服务一般都是在关闭中断的情况下执行的,以避免嵌套而是控制复杂化L ...

  4. WPF打印票据

    最近工作的内容是有关于WPF的,整体开发没有什么难度,主要是在打印上因为没有任何经验,犯了一些难,不过还好,解决起来也不是很费劲. WPF打印票据或者是打印普通纸张区别不大,只是说打印票据要把需要打的 ...

  5. 《转》高级Unix命令

    原文链接:http://coolshell.cn/articles/1044.html 在Unix操作中有太多太多的命令,这些命令的强大之处就是一个命令只干一件事,并把这件事干好.Do one thi ...

  6. 一些不太常用的Linux命令

    ACCTCOM 查看所有用户执行过的进程 acctcom | tail - 查看指定用户执行过的进程/命令 acctcom -u <username> | tail - 使用一个正则表达式 ...

  7. Python 实现队列

    操作 Queue() 创建一个空的队列 enqueue(item) 往队列中添加一个item元素 dequeue() 从队列头部删除一个元素 is_empty() 判断一个队列是否为空 size() ...

  8. 高级Unix命令

    在Unix操作中有太多太多的命令,这些命令的强大之处就是一个命令只干一件事,并把这件事干好.Do one thing, do it well.这是unix的哲学.而且Unix首创的管道可以把这些命令任 ...

  9. 数据结构之队列(Queue)

    1,队列的定义 队列:是一种先进先出的数据结构,如下图所示,现进去的数据在队列前面(front),先出队列,后进入队列的数据在后面(rear),后出队列. 队列常用操作: q=Queue() #创建队 ...

随机推荐

  1. Scrapy框架解读

    1. Scrapy组件a. 主体部分i. 引擎(Scrapy):处理整个系统的数据流处理,触发事务(框架核心)ii. 调度器(Scheduler):1) 用来接受引擎发过来的请求, 压入队列中, 并在 ...

  2. MyBatis的flushCache和useCache的使用注意

    之前在利用MyBatis做开发的时候,遇到了一个问题,使用select配置的时候发现前后两次的结果是一样的,并且使用statementType="CALLABLE"配置,然后在配置 ...

  3. C# 中的数据库操作~存储过程篇Mysql SqlServer

    Mysql 存储过程查询方式 SQL server 普通数据库操作 EF 调用SQL SERVER存储过程 Mysql 存储过程查询方式: public NetPort GetNetdevicePor ...

  4. python 37 同步、异步调用

    目录 1. 阻塞与非阻塞 2. 同步与异步 2.1 异步调用 2.2 同步调用 2.3 异步调用回收的第一种方式 3. 异步调用+回调函数 3.1 requests模块 3.2 异步调用回收的第二种方 ...

  5. Centos安装和配置Mysql5.7

    [root@localhost ~]# wget https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm -bash ...

  6. Vue 关于多个父子组件嵌套传值

    prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来.这是为了防止子组件无意修改了父组件的状态——这会让应用的数据流难以理解. props: { selectMember: { ...

  7. awrcrt更新到2.1(重大更新)

    awrcrt更新到了2.1 awrcrt迎来了最近一年的最大一次更新,从2.03直接跳跃了2.1版本.本次更新,给awrcrt带了全面的改变. 最主要的更新内容是什么呢?请看 更新了图表javascr ...

  8. java基础-多线程一

    什么是线程 说到线程就不得不说下进程了, 大家都知道,许许多多的线程组合在一起就成了一个进程,进程是由操作系统进行资源操作的一个最小的单位,线程则是比进程更小的实际执行操作的单位:每个线程都有自己的堆 ...

  9. POJ-2230-Watchcow-欧拉回路的路径输出+结构体

    Watchcow 这道题的题意好理解,就是要从1出发,每条边都走两遍,最后再回到1: 但是,我一开始没有想到和欧拉回路有什么关系: 学了求欧拉的dfs()后,试了一下发现和样例差不多: 感觉求回路,什 ...

  10. SDU暑期集训排位(8)

    A. A Giveaway 签到 B. Game of XOR 做法 dp[G][L][R]表示在倒数第G代,左边的数是L,右边的数是R,下面共有多少个0和1 区间和转换成两次前缀和和一次单点查询 利 ...