数据结构 | 基本数据结构——队列

news2024/9/22 23:30:59

目录

一、何谓队列

二、队列抽象数据类型

三、用Python实现队列

四、模拟:传土豆

五、模拟:打印任务

5.1 主要模拟步骤

5.2 Python实现


一、何谓队列

队列是有序集合,添加操作发生在“尾部”,移除操作则发生在“头部”。新元素从尾部进入队列,然后一直向前移动到头部,直到成为下一个被移除的元素。

最新添加的元素必须在队列尾部等待,在队列中时间最长的元素则排在最前面。这种排序原则被称作FIFO,即先进先出,也称先到先得。

二、队列抽象数据类型

队列抽象数据类型由下面的结构和操作定义。如前所述,队列是元素的有序集合,添加操作发生在其尾部,移除操作则发生在头部。队列的操作顺序是FIFO,它支持以下操作。

  • Queue()创建一个空队列。它不需要参数,且会返回一个空队列。
  • enqueue(item)在队列的尾部添加一个元素。它需要一个元素作为参数,不返回任何值。
  • dequeue()从队列的头部移除一个元素。它不需要参数,且会返回一个元素,并修改队列的内容。
  • isEmpty()检查队列是否为空。它不需要参数,且会返回一个布尔值。
  • size()返回队列中元素的数目。它不需要参数,且会返回一个整数。

在“队列内容”一列中,队列的头部位于右端。

三、用Python实现队列

需要确定列表的哪一端是队列的尾部,哪一端是头部。假设队列的尾部在列表的位置0处。如此一来,便可以使用insert函数向队列为尾部添加新元素。pop则可用于移除队列头部的元素(列表中的最后一个元素)。这意味着添加操作的时间复杂度是O(n),移除操作则是O(1)。

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)

q=Queue()
print(q.isEmpty())

q.enqueue('dog')
q.enqueue(4)
q=Queue()
print(q.isEmpty())

q.enqueue(4)
q.enqueue('dog')
q.enqueue(True)
print(q.size())

print(q.isEmpty())

q.enqueue(8.4)
print(q.dequeue())
print(q.dequeue())
print(q.size())

四、模拟:传土豆

展示队列用法的一个典型方法是模拟需要以FIFO方式管理数据的真实场景。考虑这样做一个儿童游戏:传土豆。在这个游戏中,孩子们围成一圈,并依次尽可能快地传递一个土豆。某个时刻,大家停止传递,此时手里有土豆的孩子就得退出游戏。重复上述过程,直到只剩下一个孩子。

我们将针对传土豆游戏实现通用的模拟程序。该程序接受一个名字列表和一个用于计数的常数num,并且返回最后一人的名字。

我们使用队列来模拟一个环。假设握着土豆的孩子位于队列的头部。在模拟传土豆的过程中,程序将孩子的名字移出队列,然后立刻将其插入队列的尾部。随后,这个孩子会一直等待,直到再次到达队列的头部。在出列和入列num次之后,此时位于队列头部的孩子出局,新一轮游戏开始。如此反复,直到队列中只剩下一个名字(队列的大小为1)。

from pythonds.basic 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))

五、模拟:打印任务

考虑计算机实验室里的这样一个场景:在任何给定的一小时内,实验室里都有约10个学生。他们在这一小时内最多打印2次,并且打印的页数从1到20不等。实验室的打印机比较老旧,每分钟只能以低质量打印10页。可以将打印质量调高,但是这样做会导致打印机每分钟只能打印5页。降低打印速度可能导致学生等待过长时间。

可以通过构建一个实验室模型来解决该问题。我们需要学生、打印任务和打印机构建对象。当学生提交打印任务时,我们需要将它们加入等待列表中,该列表是打印机上的打印任务队列。当打印机执行完一个任务后,它会检查该队列,看看其中是否还有需要处理的任务。我们感兴趣的是学生平均需要等待多久才能拿到打印好的文章。这个时间等于打印任务在队列中的平均等待时间。

在模拟时,需要应用一些概率学知识。举例来说,学生打印的文章可能有1~20页。如果各页数出现的概率相等,那么打印任务的实际时长可以通过1~20的一个随机数来模拟。

如果实验室有10个学生,并且在一小时内每个人都打印两次,那么每小时平均就有20个打印任务。每小时20个任务相当于每180秒1个任务。

可以通过1~180的一个随机数来模拟每秒内产生打印任务的概率。如果随机数正好是180,那么就认为有一个打印任务被创建。注意,可能会出现多个任务接连被创建的情况,也可能很长一段时间内没有任务。

5.1 主要模拟步骤

(1)创建一个打印任务队列。每一个任务到来时都会有一个时间戳。一开始,队列是空的。

(2)针对每一秒(currentSecond),执行以下操作。

  • 是否有新创建的打印任务?如果是,以currentSecond作为其时间戳并将该任务加入到队列中。
  • 如果打印机空闲,并且有正在等待执行的任务,执行以下操作:
  1. 从队列中取出第一个任务并提交给打印机;
  2. 用currentSecond减去该任务的时间戳,以此计算其等待时间;
  3. 将该任务的等待时间存入一个列表,以备后用;
  4. 根据该任务的页数,计算执行时间。
  • 打印机进行一秒的打印,同时从该任务的执行时间中减去一秒。
  • 如果打印任务执行完毕,或者说任务需要的时间减为0,则说明打印机回到空闲状态。

(3)当模拟完成后,根据等待时间列表中的值计算平均等待时间。

5.2 Python实现

我们创建3个类:Printer、Task和PrintQueue。它们分别模拟打印机、打印任务和队列。

Printer类需要检查当前是否有待完成的任务。如果有,那么打印机就处于工作状态,并且其工作所需的时间可以通过要打印的页数来计算。其构造方法会初始化打印速度,即每分钟打印多少页。tick方法会减量计时,并且在执行任务之后将打印机设置成空闲状态。

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
            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

Task类代表单个打印任务。当任务被创建时,随机数生成器会随机提供页数,取值范围是1~20.我们使用random模块中的randrange函数来生成随机数。

import random
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

主模拟程序实现了之前描述的算法。printQueue对象是队列抽象数据类型的实例。布尔辅助函数newPrintTask判断是否有新创建的打印任务。我们再一次使用random模块中的rangrange函数来生成随机数,不过这一次的取值范围是1~180.平均每180秒有一个打印任务。通过从随机数中选取180,可以模拟这个随机事件。该模拟程序允许设置总时间和打印机每分钟打印多少页。

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
            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


import random


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


from pythonds.basic import Queue
import random

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()))

def newPrintTask():
    num=random.randrange(1,181)
    if num==180:
        return True
    else:
        return False

for i in range(10):
    simulation(3600,5)

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/823863.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Javascript】基础知识

文章目录 01 变量的声明02 数据类型字符串型boolean类型undefined null类型symbol类型超大整数 bigint数组类型普通对象 01 变量的声明 02 数据类型 复习: 声明 ​ 声明变量关键词 ​ let ​ const ​ 变量名 >变量命名规范 ​ 英文 数字 _ $不要以数字开头 ​ 见名知意 ​…

深度学习之tensorboard可视化工具

(1)什么是tensorboard tensorboard是TensorFlow 的一个可视化工具包&#xff0c;提供机器学习实验所需的可视化和工具&#xff0c;该工具的功能如下&#xff1a; 跟踪和可视化指标&#xff0c;例如损失和精度可视化模型图&#xff08;操作和层&#xff09;查看权重、偏差或其…

【Java多线程学习4】volatile关键字及其作用

说说对于volatile关键字的理解&#xff0c;及的作用 概述 1、我们知道要想线程安全&#xff0c;就需要保证三大特性&#xff1a;原子性&#xff0c;有序性&#xff0c;可见性。 2、被volatile关键字修饰的变量&#xff0c;可以保证其可见性和有序性&#xff0c;但是volatile…

uniApp 对接安卓平板刷卡器, 读取串口数据

背景: 设备: 鸿合 电子班牌 刷卡对接 WS-B22CS, 安卓11; 需求: 将刷卡器的数据传递到自己的App中, 作为上下岗信息使用, 以完成业务; 对接方式: 1. 厂家技术首先推荐使用 接收自定义广播的方式来获取, 参考代码如下 对应到uniApp 中的实现如下 <template><view c…

python数据可视化Matplotlib

1.绘制简单的折线图 # -*- coding: utf-8 -*- import matplotlib.pyplot as pltinput_values [1, 2, 3, 4, 5] squares [1, 4, 9, 16, 25] plt.style.use(seaborn) fig, ax plt.subplots() ax.plot(input_values, squares, linewidth3) # 线条粗细# 设置图表标题并给坐标…

2023年第四届“华数杯”数学建模思路 - 复盘:光照强度计算的优化模型

文章目录 0 赛题思路1 问题要求2 假设约定3 符号约定4 建立模型5 模型求解6 实现代码 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 问题要求 现在已知一个教室长为15米&#xff0c;宽为12米&#xff0…

less的使用

less的介绍&#xff1a; less使用 1、 less使用的第一种用法&#xff0c;起变量名&#xff0c;变量名区分大小写&#xff1a; 这里我们定义一个粉色变量 我想使用直接把变量拿过来就行 2、vscode使用插件&#xff0c;直接将Css文件转换less文件&#xff1a; 3、第二种用法&…

8.泛型

目录 1 基本使用 2 多个泛型 3 泛型约束 3.1 数组 3.2 extends约束 3.3 用泛型约束泛型 4 泛型接口 5 ts中的数组用的就是泛型 6 泛型类 7 常用泛型工具类型 7.1 让所有属性变为可选属性 Partial 7.2 将所有属性都变为只读属性 Readonly 7.3 从指定类…

git-版本控制器

集中式版本控制工具&#xff08;不常用&#xff09; 版本库集中于中央服务器&#xff0c;team要联网才能工作&#xff08;下载代码&#xff09; SVN CVS 分布式版本控制工具 每个电脑上都有一个完整的版本库&#xff0c;工作时无需联网&#xff0c;可以把修改推送给其他人来…

ThreadLocal有内存泄漏问题吗

对于ThreadLocal的原理不了解或者连Java中的引用类型都不了解的可以看一下我的之前的一篇文章Java中的引用和ThreadLocal_鱼跃鹰飞的博客-CSDN博客 我这里也简单总结一下: 1. 每个Thread里都存储着一个成员变量&#xff0c;ThreadLocalMap 2. ThreadLocal本身不存储数据&…

python爬虫(四)_urllib2库的基本使用

本篇我们将开始学习如何进行网页抓取&#xff0c;更多内容请参考:python学习指南 urllib2库的基本使用 所谓网页抓取&#xff0c;就是把URL地址中指定的网络资源从网络流中读取出来&#xff0c;保存到本地。在Python中有很多库可以用来抓取网页&#xff0c;我们先学习urllib2。…

docker minio安装

1.介绍 Minio是一款开源的对象存储服务&#xff0c;它可以在任何硬件或云平台上提供高性能、高可用性和高安全性的存储解决方案。Minio最新版是2021年11月发布的RELEASE.2021-11-24T23-19-33Z&#xff0c;它带来了以下几个方面的改进和新特性&#xff1a; - 支持S3 Select AP…

Allegro选择暗显模式仍然无法实现暗显模式的解决办法

Allegro选择暗显模式仍然无法实现暗显模式的解决办法 用Allegro进行PCB设计的时候,时常需要使用到暗显模式,让视图中未被高亮的图形暗显下去,如下图 左边是未高亮的网络,右边是已高亮的 但是有时候因为一些原因,导致无法暗显,如下图 下面介绍如何解决这个问题,具体操作…

CSPM认证的价值?

最近 CSPM 证书很热门&#xff0c;含金量高&#xff0c;CSPM证书虽然发起的时间不长&#xff0c;但获取 CSPM 证书也是目前发展的一个趋势。如果打算在项目管理领域发展的强烈建议尽快获取 CSPM&#xff0c;提前为自己积攒一些资本。 一、什么是 CSPM证书&#xff1f;跟PMP是什…

Java-API简析_java.io.FileWriter类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/132038909 出自【进步*于辰的博客】 因为我发现目前&#xff0c;我对Java-API的学习意识比较薄弱…

elasticsearch 将时间类型为时间戳保存格式的时间字段格式化返回

dsl查询用法如下&#xff1a; GET /your_index/_search {"_source": {"includes": ["timestamp", // Include the timestamp field in the search results// Other fields you want to include],"excludes": []},"query": …

DevOps系列文章之 Docker 安装 NFS 服务器

Docker 安装 NFS 服务器 环境&#xff1a; 192.186.2.105 NFS 服务器 192.168.2.106 Client 客户端 安装 一、服务器端 https://github.com/f-u-z-z-l-e/docker-nfs-server 1、创建目录 mkdir /nfsdata mkdir -p /docker/nfs/2、启动脚本 vim start.sh# 内容 docker run …

ConCurrentHashMap常见面试题

1. JDK1.7和JDK1.8中ConCurrentHashMap的实现有什么不同&#xff1f; JDK1.7中的实现可以认为是大数组套小数组&#xff0c;大数组是Segment数组&#xff0c;小数组是HashEntry数组&#xff0c;锁是锁在大数组的元素上&#xff08;Segment&#xff09;&#xff0c;力度比较大&…

使用vs 2017 C#项目发布

C#项目发布 vs 2017 打包项目源代码 (发布)iis 配置添加ssl 配置 vs 2017 打包项目源代码 (发布) iis 配置 添加ssl 配置 https://help.aliyun.com/zh/ssl-certificate/user-guide/install-ssl-certificates-on-iis-servers

软考A计划-系统集成项目管理工程师-项目沟通管理-上

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列点击跳转>蓝桥系列 &#x1f449;关于作者 专注于Android/Unity和各种游…