python数据结构与算法 16 队列应用之 打印任务

Python之队列模拟算法(打印机问题) 模拟打印机问题: 如果平均每天任意一个小时实验室里都有10个学生,并且每人需要发起2次打印任务,平均每小时就有20个打印任务,即平均每180秒生成一个打印任务,那么,在任意一秒,产生一个打印任务的概率就是1/180,每个打印任务的页数从1到20页不等,计算平均等待时长。 以下为主要的模拟过程: 1、创建一个打印任务队列。每个任务在生成时被赋予一个“时间节点”。队列在开始时是空的。 2、对于每一秒(... 阅读详情

队列应用:打印任务

在本章开始我们就谈到过模拟打印任务队列的行为。回想学生时代,向共享打印机发送一个打印任务,并被放在一个先到先服务的队伍中等候处理。这种方法有很多的问题,最重要的是,打印机是否能够完成这么多数量的任务,如果打不完,学生们会等待太长时间,导致错过下次课。

考虑一下这种情形:计算机科学实验室里,平均每小时有10个学生在完成作业,这些个学生在这段时间里一般打印两次,每次任务可能是1-20页不等。实验室的打印机有点老,按草稿质量能够打印10页/分钟,如果切换到高质量,则只能打印5页/分钟,越慢等的时候越长,那么应该设置成多少?

我们可以通过建立一个实验室模型帮助决策。需要建立学生,打印任务和打印机的的模型。因为学生发出打印任务时,需要把任务加入打印任务队列。当打印机完成一个任务后,它要到队列中查看是还仍有任务要处理。我们感兴趣的是,学生们的平均等待时间,也等同于队列中任务的平均等待时间。


这个模型需要一点概率事件,例如,学生打印长度1-20页,如果每个长度可能性相等,那么实际长度可以用一个1-20之间的随机数来模拟。这表示,1-20之间的长度机会均等。

如果10个学生每人打印两次,那么平均每小时有20个打印任务。在每一秒钟产生一个打印任务的可能性多大?这就要考虑任务与时间的比率。20个任务每小时,意味着平均每180秒产生一个任务。

20任务/小时 ×1小时/60钟×1分钟/60秒=1任务/180秒

我们可以通过产生一个1-180之间的随机数,来模拟每秒钟产生一个新任务的概率。如果数字是180,那么任务已经产生了。要注意很多任务可能排成队,也有可能等好久也没有一个任务,这就是模拟的特性,我们的模拟总是想尽可能地接近真实情况。


主要模拟步骤

主要分这几个步骤。

  1. 建立打印任务队列,每个任务要打上到达的时间戳,开始时是空的队列。
  2. 对每一秒(currentSecond)

    2.1有没有新任务到达?如果有,如果有,加入队列,加上(currentSecond)时间戳。

    2.2如果打印机空闲且有任务在等待:

    2.2.1从队列中除去下一个任务,并分配给打印机。

    2.2.2当前时间减去加入队列的时间戳,就是本任务的等待时间

    2.2.3把等待时间加入一个列表,后续处理。

    2.2.4根据本任务的纸张数,计算打印所需时间
2.3如果需要,打印机工作1秒钟,也要从任务所需时间中减去1秒钟

2.4如果打印完成,也就是上一步中把时间减到0了,打印机进入空闲状态

3.模拟完成,根据任务时间列表,计算平均等待时间


Python实现

为了实现任务模拟,我们设计三个类对应现实世界的三种对象:Printer,Task,和 PrintQueue

Printer 类用来跟踪当前是否在工作,如果是,它的状态是busy(13-17),并且busy时间用纸张数计算出来。构造函数可以设置每分钟打印页数。Tikc方法递减内部时间,并将打印机设为idle(11行)

Listing2

class Printer:

    def__init__(self, ppm):

       self.pagerate = ppm

       self.currentTask = None

       self.timeRemaining = 0

 

    deftick(self):

        ifself.currentTask != None:

           self.timeRemaining = self.timeRemaining - 1

            ifself.timeRemaining <= 0:

                self.currentTask = None

 

    defbusy(self):

        ifself.currentTask != None:

           return True

        else:

           return False

 

    defstartNext(self,newtask):

       self.currentTask = newtask

       self.timeRemaining = newtask.getPages() * 60/self.pagerate


Task类代表一个打印任务。产生任务时,构造函数提供一个1-20之间的随机数,代表任务的纸张数。要用到random模块的randrange 方法


>>> importrandom
>>> random.randrange(1,21)
18
>>> random.randrange(1,21)
8
>>> 

每个任务也要保存一个时间戳用来计算等待时间。这个时间戳代表产生任务并加入队列的时间,waitTime方法用来计算任务在开始打印之前等待的时间。


Listing3

import random

 

class Task:

    def__init__(self,time):

        self.timestamp =time

        self.pages =random.randrange(1,21)

 

    def getStamp(self):

        returnself.timestamp

 

    def getPages(self):

        return self.pages

 

    def waitTime(self,currenttime):

        return currenttime- self.timestamp

 

模拟程序(Listing 4)用来实现上面所述的算法。printQueue对象是队列的抽象数据类型的实例,一个布尔值辅助函数,newPrintTask用来决定是否有新任务产生,我们再次使用了random模块randrange方法返回一个1-180之间的随机数。打印任务每180秒到来一次,我们从一个范围内的随机整数中产生180的方法模拟随机事件(32行)。这个模拟功能允许我们设置总时间和打印机的打印速度。

frompythonds.basic.queueimport Queue
 
importrandom
 
defsimulation(numSeconds, pagesPerMinute):
 
   labprinter = Printer(pagesPerMinute)
   printQueue = Queue()
   waitingtimes = []
 
    for currentSecondinrange(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()))
 
defnewPrintTask():
   num = random.randrange(1,181)
    if num==180:
       returnTrue
    else:
       returnFalse
 
for iinrange(10):
   simulation(3600,5)

运行模拟程序时,对于每次运行的结果不同不必担心,这是随机数的原因,我们感兴趣的是,如果调整模拟参数,模拟程序的变化趋势。这里是一组测试数据。

首先,我们要运行模拟程序60分钟(3600秒),使用1台5ppm的打印机,一共运行10次测试。再说一遍,因为随机数的原因,每次测试的结果不同。

>>>for i in range(10):

     simulation(3600,5)

 

Average Wait 165.38 secs 2 tasks remaining.

Average Wait  95.07 secs 1 tasks remaining.

Average Wait  65.05 secs 2 tasks remaining.

Average Wait  99.74 secs 1 tasks remaining.

Average Wait  17.27 secs 0 tasks remaining.

Average Wait 239.61 secs 5 tasks remaining.

Average Wait  75.11 secs 1 tasks remaining.

Average Wait  48.33 secs 0 tasks remaining.

Average Wait  39.31 secs 3 tasks remaining.

运行10次以后,我们能看得出平均等待时间是122.155秒,也能看到平均数据变化的范围很大,从最小的17.27秒到最大的239.61秒,而且只有2次的打印任务是完成的。

现在我们调整打印速度到10ppm,再运行10次,通过更快的打印机任务,我们希望在一个小时的时间里,有更多的打印任务得以完成。

>>>for i in range(10):

     simulation(3600,10)

 

Average Wait   1.29 secs 0 tasks remaining.

Average Wait   7.00 secs 0 tasks remaining.

Average Wait  28.96 secs 1 tasks remaining.

Average Wait  13.55 secs 0 tasks remaining.

Average Wait  12.67 secs 0 tasks remaining.

Average Wait   6.46 secs 0 tasks remaining.

Average Wait  22.33 secs 0 tasks remaining.

Average Wait  12.39 secs 0 tasks remaining.

Average Wait   7.27 secs 0 tasks remaining.

Average Wait  18.17 secs 0 tasks remaining.

附完整代码:

from pythonds.basic.queue import Queue
 
import random
 
class Printer:
    def __init__(self, ppm):
        self.pagerate = ppm
        self.currentTask =None
        self.timeRemaining = 0
 
    def tick(self):
        if self.currentTask !=None:
            self.timeRemaining= self.timeRemaining - 1
            ifself.timeRemaining <= 0:
                self.currentTask = None
 
    def busy(self):
        if self.currentTask !=None:
            return True
        else:
            return False
 
    defstartNext(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 simulation(numSeconds, pagesPerMinute):
 
    labprinter =Printer(pagesPerMinute)
    printQueue = Queue()
    waitingtimes = []
 
    for currentSecond inrange(numSeconds):
 
      if newPrintTask():
         task =Task(currentSecond)
        printQueue.enqueue(task)
 
      if (notlabprinter.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()))
 
def newPrintTask():
    num =random.randrange(1,181)
    if num == 180:
        return True
    else:
        return False
 
for i in range(10):
simulation(3600,5)


讨论

这次模拟的目的,是要问题这样一个问题,即通过降低打印速度提高打印皁,这台打印机是否能够承担这个打印负荷。这个过程就是编写一个模拟程序,为打印任务建模,并以随机的发生时间和随机的工作长度进行验证。

以上的输出表明,如果在5ppm的速度,平均等待时间是从17秒到376秒(约6分钟),如果用速度加快,最小时间变为1秒到28秒。另外在5ppm的速度下,8成的打印任务在1个小时内没有打完。

这样,我们会给出建议说,提高质量降低速度,不是一个好办法。学生们不能等那么长时间来等待,特别是下一节还有课,6分钟的等待太长了。

这种模拟分析能够回答很多问题,特别是这类“如果怎样,那么怎样”类的问题,因为我们只要修改模拟程序的参数,就能模拟很多有趣的行为。比如

  • 如果人数增多,现在有20个学生,是什么情形?
  • 如果是周六,学生们不必去上课,他们会等待吗?
  • 因为python语言太强大了,程序都变短,所以学生们的打印任务都变小了,会怎么样?

这些问题都可能修改模拟参数来得到答案,当然,必须明白,模拟程序只是使用可能真实假定数据。现实中的打印任务长度和每小时内要打印的学生数,也需要构建一个模拟程序。。


《Python数据结构与算法分析》第三章课后习题 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、课后习题 前言 最近开始学数据结构,打算用python作为语言,看的书是米勒和戴维的《Python数据结构与算法分析》。目前大三,希望能一个月速成,奥利给!!注意到课本中的练习题没有参考答案,我自己写了一份放到这上面,更详细,完整的代码在我的github:https://github.com/Yunzz-goon/PythonForDataStructure 欢迎大家一起交流!!! ———————————————————— 阅读详情

相关推荐

Python数据结构与算法—队列

文章目录一、基本概念二、代码实现三、deque模块四、迷宫问题方法一:栈方法二:队列 一、基本概念 1.定义:队列是限制在两端进行插入操作和删除操作的线性表,允许进行存入操作的一端称为“队尾”,允许进行删除操作的一端称为“队头”。 2.特点: 1、队列只能在队头和队尾进行数据操作 2、栈模型具有先进先出或者叫做后进后出的规律 二、代码实现 主要使用队列的顺序储存 思路分析: 通过环形队列,如下图 环形队列:当队尾指针 front == Maxsize + 1 时,再前进一个位置就自动到0 队首指针

qq_39280718的博客 412

python—队列的应用:打印任务

2如果打印机空闲,且队列不空,则取出队首作业打印,记录此作业等待时间。打印队列(具有FIFO性质的打印任务队列)3如果打印机忙,则按照打印速度进行1秒打印。4如果当前作业打印完成,则打印机进入空闲。1按照概率生成打印作业,加入打印队列。打印机(打印速度/是否忙)对象:打印任务(提交时间和打印页数)过程:时间按照秒的单位流逝。

glaciet的博客 454

【Python学习教程】数据结构与算法

python内置的数据结构包括:列表(list)、集合(set)、字典(dictionary),一般情况下我们可以直接使用这些数据结构,但通常我们还需要考虑比如搜索、排序、排列以及赛选等一些常见的问题。如何巧妙的使用数据结构和同数据有关的算法,在collections模块中包含了针对各种数据结构的解决方法。列1:使用collections.deque保存有限的历史纪录,deque用来创建一个固定长度的队列#创建队列长度对象加入数据到队列从左边加入数据到队列从末尾取出一个数据。

aliYz的博客 861

Linux input子系统 (2)

<br />原文:http://www.linuxjournal.com/article/6429<br />尽管原文写于2003,仍有参考价值。<br /> <br /> <!-- @page { size: 8.5in 11in; margin: 0.79in } P { margin-bottom: 0.08in } H4 { margin-bottom: 0.08in } TD P { margin-bottom: 0in } --> <

Lanttor的技术博文 1万+

数据结构实验一打印队列 实验报告 内含源代码

数据结构的作业 打印机队列的实验报告 其中内含源代码 方便实用 C++描述

Python算法应用实战之队列详解

队列是一种先进先出(First-In-First-Out,FIFO)的数据结构。队列被用在很多地方,比如提交操作系统执行的一系列进程、打印任务池等,一些仿真系统用队列来模拟银行或杂货店里排队的顾客。下面就介绍了Python中队列的应用实战,需要的可以参考。

Python数据结构——队列 模拟队列打印问题

当学生提交打印任务时,我们需要将它们加入等待列表中,该列表是打印机上的打印任务队列。当打印机执行完一个任务后,它会检查该队列,看看其中是否还有需要处理的任务。如果有,那么打印机就处于工作状态,并且其工作所需的时间可以通过要打印的页数来计算。上面的输出结果显示,按每分钟5页的打印速度,任务的等待时间在23.85秒和313.94秒之间,相差约5分钟。我们编写了一个程序来模拟随机提交的打印任务,待打印的页数也是随机的。如果各页数出现的概率相等,那么打印任务的实际时长可以通过1-20的一个随机数来模拟。

ZY_yin的博客 1743

智驾域控制器硬件架构:从接口丛林到算力核心的工程解码

本文深入解析了智驾域控制器硬件架构的设计挑战与工程实践。面对复杂的接口丛林,文章详细探讨了如何高效融合摄像头、雷达等多源传感器数据,并构建以多SOC为核心的强大算力平台。同时,文章强调了电源、时钟、散热等最小系统及车规级可靠性设计的关键作用,为工程师提供了从接口驯服到算力核心协同的完整硬件解码指南。

happy2的博客 482

Python数据结构与算法分析(第二版)

对列表进行加长操作,比较不同方法的性能pop性能分析。

aha_xigua的博客 2550

金蝶ERP元数据解析:字段属性与表结构映射实战

本文深入解析金蝶ERP元数据的核心价值与应用实践,详细介绍了字段属性与表结构映射的关键技术。通过缓存获取与工具类直连两种方案对比,结合实际案例展示元数据在数据库校验、动态表单生成等场景的应用,帮助开发者高效解决二次开发中的常见问题。

weixin_33738555的博客 433

「点燃我,温暖你」用Python制作一个动态爱心效果

最近「点燃我,温暖你」这部剧非常火,讲述的是程序员的爱情故事。其中陈飞宇饰演的男主李峋,在剧中用程序做出的爱心跳动效果,非常炫。

Modeler_xiaoyu的博客 1万+

队列python(数据结构与算法)--优先队列

"""优先级队列""" #优先级队列是在普通队列的基础上将队列中的数据元素按照 #关键字的值进行有序的排序 #优先级队列在队首进行删除的操作,但为了保证队列的优先级顺序 #插入操作不一定在队列的尾部进行 #优先级队列可以由链表和顺序表实现, #但为了快速的访问高级的元素和快速的插入元素,通常使用链式存储结构。 ...

qq_33465047的博客 775

如何理解Fourier Neural Operator (FNO)

2022年Nvidia发表在arXiv上的的FourcastNet作为几乎是最早的一篇气象大模型的工作(之前Google Research的MetNet主要还是对于降水的预报)。除了Transformer的backbone之外,使用到了2021年发表在ICLR上的Fourier Neural Operator。为了更好的理解模型的理论基础,可以详细学习一下以及他的前期工作GNOFNO作者对这两篇文章的解析blog。

momo的博客 1万+

队列(queue)应用及python实现——约瑟夫问题

何为队列(Queue) 1.1 定义:队列是一种有次序的数据集合,其特征为:“先进先出” (1)新数据的添加总是从尾端发生(rear端) (2)新数据的移除总是在首端发生(front端) 当数据加入队列是,首先在对尾,逐渐移除队首数据,它逐渐接近队首。 1.2 生活中应用案例: (1)一台打印机面向多个用户/程序提供服务 (2)操作系统核心采用多个队列对系统中同时运行的进程进行调度,原则为“先到先...

cy15625010944的博客 2147

Remote ID的调制解调FPGA实现

Remote ID源于航空安全需求,例如在无人机密集区域实现设备跟踪和防碰撞。它类似于航空领域的ADS-B系统,但针对低空飞行器。Remote ID系统通常工作在特定频段(如2.4 GHz或5.8 GHz),通过无线链路广播数据包,包含设备ID、经纬度、高度和速度等信息。调制解调过程确保这些数据在噪声环境中可靠传输。例如,标准如ASTM F3411定义了Remote ID的协议框架,其中调制解调是关键物理层组件。

yulongfenghu的博客 1506

华为OD机试真题2025双机位A卷 Java&Go 实现【优美子数组】

华为OD机试真题2025双机位A卷 Java&Go 实现【优美子数组】

MISAYAONE的博客 239

数据结构第四章笔记

数据结构笔记 目录数据结构笔记第四章队列抽象数据类型及 python 实现什么是队列抽象数据类型 Queue 的操作队列的实现队列的应用:热土豆队列的应用:打印任务问题模拟对问题建模模拟流程双端队列抽象数据类型及 python 实现无序表抽象数据类型及 python 实现列表(无序表) list采用链表实现无序表链表实现:节点 Node链表实现:无序表 UnorderedList无序表的链表实现有序表抽象数据类型及 python 实现链表实现的算法分析线性结构小结 第四章 队列抽象数据类型及 pytho

weixin_44044521的博客 1346

PCL 快速均匀下采样

快速均匀下采样 是一种点云降采样技术,通过设置采样步长来实现等距降采样,从而减少点的数量。用户可以通过指定步长,选择每隔一定数量的点采样一个点,这样可以在保持点云几何特性的同时,显著减少点的数量。

纵马踏花向自由 870

python 队列 一次取多个_数据结构系列:栈?队列?这俩货应该这么理解和掌握

上篇文章 数据结构系列:列表?线性表?这俩货到底什么关系?我们主要介绍了线性表的经典实现之一:列表。本篇将主要分享栈和队列这两种线性表结构的特点和一些经典应用。代码都是基于python语言。栈概念栈(stack)是一种数据结构,属于线性表的一种实现。既然是线性表,那么肯定数据之间也有一定的特征,栈的特征如下数据项的加入和移除都限制在一端,这个端点一般称之为栈顶专业点的描述就是:后进先出(LIFO)...

weixin_39840729的博客 428

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

python教程:数据结构与算法

python教程:数据结构与算法

Python热爱者的博客 787

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

python 链表如何打印

深入理解Python中的链表打印 链表是数据结构中重要的一种,常用于为复杂数据解决问题。与数组不同,链表通过指向下一个节点的指针存储数据,因此在插入和删除操作上有一定的优势。在本文中,我们将探讨如何在Python中实现一个简单的链表,并介绍如何打印链表的内容。通过这个过程,我们可以处理一个实际问题——实现一个任务调度程序,...

weixin_29846499的博客 227

【数据结构与算法——python】基本结构

基本结构 栈 class Stack: def __init__(self): self.items = [] def isEmpty(self): return self.items == [] def push(self, item): self.items.append(item) def pop(self...

ZhShy 405

【数据结构】实验一:栈和队列(Python版)

实验一:栈和队列 一、实验题目 1.数制转换问题 2.求后缀表达式 3.舞会 4.连通块 假设在周末舞会上,男士们和女士们进入舞厅时,各自排成一队。跳舞开始时,依次从男队和女队的队头上各出一人配成舞伴。规定每个舞曲能有一对跳舞者。若两队初始人数不相同,则较长的那一队中未配对者等待下一轮舞曲。现要求写一个程序,模拟上述舞伴配对问题。 一个n × m的方格图,一些格子被涂成了黑色,在方格图中被标为1,白色格子标为0。问有多少个四连通的黑色格子连通块。四连通的黑色格子连通块指的是一片由黑色格子组成的区域.....

ChristensonLee的博客 686

数据结构与算法Python版(完整版)P8

大O表示法 Python数据结构 抓大头,数量级 决定运行时间的不仅是问题规模,还跟工况有关,平均状况 常见的七种 P10 变位词判断问题 问题: 解法1 解法2:先排序后比较 def paiXU(s1,s2): a=list(s1) b=list(s2) a.sort() b.sort() pos=0 matches=True ...

weixin_43332626的博客 1577

面试必备:Python数据结构与算法50题精讲

在竞争激烈的IT面试中,数据结构与算法能力往往是衡量候选人技术实力的核心标准。本文精选50道Python数据结构与算法经典面试题,涵盖数组、链表、树、图等核心知识点,通过系统化讲解帮助你快速掌握解题思路与技巧,轻松应对各类技术面试挑战。 ## 一、数组与矩阵类题目 ### 1. 二维数组中的查找 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一

gitblog_00195的博客 478
上一篇: PyQt4之对话框示例
下一篇: python数据结构与算法 17 列表
杀了这个男孩
博客等级 码龄18年 149粉丝 38原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值