zoukankan      html  css  js  c++  java
  • 数据结构与算法(7)——队列Queue

    • 队列基础定义

    队列:一种有次序的数据集合。其特点是新数据项的添加总发生在尾端(rear)而现存数据项的移除总发生在另一端(首端front),先进先出

    队列只有一个入口,一个出口。当数据加入队列,首先出现在队尾,随着首数据项的移除,它逐渐接近队首。不允许数据项直接插入队中,也不允许从中间移除数据项(可联想成水管流动,排队等情况)

    •  抽象数据类型Queue类型-python
    Queue() 创建一个空队列对象,返回值为Queue对象
    enqueue(item) 将数据项item添加到队尾,无返回值
    dequeue() 从队首移除数据项,返回值为队首数据项,队列被修改
    isEmpty() 测试队列是否为空,返回值为bool类型
    size() 返回队列中数据项的个数

    用python自定义一个队列:

     1 class Queue:
     2     def __init__(self):
     3         self.items = []
     4 
     5     def isEmpty(self):
     6         return self.items == []
     7 
     8     def enqueue(self, item): #复杂度O(n)
     9         self.items.insert(0,item)
    10 
    11     def dequeue(self): #复杂度O(1)
    12        return self.items.pop()
    13 
    14     def size(self):
    15         return len(self.items)
    16 Q = Queue()
    17 Q.enqueue(0)
    18 Q.enqueue(1)
    19 Q.enqueue('a')
    20 print(Q.size())
    [OUT]
    3
    
    Process finished with exit code 0
    • 队列的应用
    1. 热土豆问题(约瑟夫问题)

    问题描述:传烫手的热土豆,鼓声停的时候,手里有土豆的小朋友需要出列。(不想敲字了,直接截图PPT)

     分析:用队列来实现。用Queue存放所有参加游戏的人名,队首默认为拥有土豆的人,游戏开始,队首的人出列,然后随即到队尾入队,记为土豆的一次传递,传了num次后,将队首的人移除,不再入队,如此反复,直到队列中只剩一个人。

     代码:

     1 from queue1 import Queue
     2 
     3 def hotPotato(namelist, num):
     4     simqueue = Queue()
     5 
     6     for name in namelist:
     7         simqueue.enqueue(name)
     8 
     9     while simqueue.size() >1:
    10         for i in range(num):
    11             simqueue.enqueue(simqueue.dequeue())  #一次传递
    12 
    13         simqueue.dequeue()
    14     return simqueue.dequeue()
    15 print(hotPotato(['a','b','c','d','e','f','g'],7))
    d
    
    Process finished with exit code 0

        2.模拟打印任务(这部分内容结合数学建模知识)

    问题:多人共享一台打印机,采用先到先服务的策略来执行打印任务。(直接截图条件)问题是怎么设定打印机的模式,让大家都不会等太久的前提下,尽量提高打印质量?

    问题建模:首先需要确定打印机3个对象的属性:1.打印任务属性——是提交时间和打印页数,2.打印队列属性——是就队列性质的打印任务,3.打印机属性——打印速度和是否繁忙。然后确定打印任务的生成概率为:1/180(每秒),打印页数1~20之间概率相等,随机取即可。

    一个简单的打印机任务模拟代码:

     1 from queue1 import Queue
     2 import random
     3 
     4 class Printer: #建立打印机属性
     5     def __init__(self,ppm):
     6         self.pagerate = ppm #打印速度
     7         self.currentTask = None #打印任务
     8         self.timeRemaining = 0 #当前正在打印的任务还剩的时间
     9 
    10     def tick(self):
    11         '''
    12         打印1秒,即如果当前有打印作业,任务倒计时减1,当减到小于0,则当前任务结束了
    13         '''
    14         if self.currentTask !=None:
    15             self.timeRemaining = self.timeRemaining - 1
    16             if self.timeRemaining <=  0:
    17                 self.currentTask = None
    18 
    19     def busy(self):
    20         '''
    21         判断打印机是否繁忙
    22         '''
    23         if self.currentTask != None:
    24             return True
    25         else:
    26             return False
    27 
    28     def startNext(self,newtask):
    29         '''
    30         开始打印新作业
    31         :param newtask: 新的打印作业
    32         :return:
    33         '''
    34         self.currentTask = newtask #将当前打印对象设置为新的作业
    35         self.timeRemaining = newtask.getPages() * 60 / self.pagerate #计算作业需要打印多久,/s为单位
    36 
    37 class Task: #建立打印任务属性
    38     def __init__(self,time):
    39         self.timestamp = time #生成时间戳
    40         self.pages = random.randrange(1,21) #随机数指定打印作业页数
    41     def getStamp(self): #返回生成时间戳
    42         return self.timestamp
    43     def getPages(self): #返回页数
    44         return self.pages
    45     def waitTime(self,currentime):
    46         return currentime - self.timestamp #这个打印任务被等了多少时间
    47 
    48 def newPrintTask():
    49     num = random.randrange(1,181) #以1/180概率生成作业
    50     if num == 180:
    51         return True
    52     else:
    53         return False
    54 
    55 def simulation(numSeconds, pagesPerMinute):
    56     '''
    57     模拟打印机
    58     :param numSeconds: 模拟多长时间(一段时间长度)
    59     :param pagesPerMinute:打印机设定模式,即打印速度,每分钟多少页
    60     :return:
    61     '''
    62     labpriter = Printer(pagesPerMinute)
    63     printQueue = Queue() #准备一个打印队列
    64     waitingtimes = [] #等待时间
    65     for currentSecond in range(numSeconds):
    66         if newPrintTask(): #如果需要打印新任务,生成打印作业
    67             task = Task(currentSecond) #记录开始打印时间戳
    68             printQueue.enqueue(task) #记录打印任务队列
    69         if (not labpriter.busy()) and (not printQueue.isEmpty()): #如果打印机空闲,且打印任务存在
    70             nexttask = printQueue.dequeue()
    71             waitingtimes.append(nexttask.waitTime(currentSecond))
    72             labpriter.startNext(nexttask)
    73         labpriter.tick()
    74     averageWait= sum(waitingtimes)/len(waitingtimes)
    75     print('平均等待 %6.2f 秒,还有 %3d 打印任务剩余'%(averageWait,printQueue.size()))
    76 for i in range(10):
    77     simulation(36000,5)
    [out]
    平均等待 201.74 秒,还有   2 打印任务剩余
    平均等待 151.27 秒,还有   1 打印任务剩余
    平均等待 191.02 秒,还有   1 打印任务剩余
    平均等待 269.86 秒,还有   0 打印任务剩余
    平均等待 276.02 秒,还有   2 打印任务剩余
    平均等待 226.06 秒,还有   1 打印任务剩余
    平均等待  74.98 秒,还有   3 打印任务剩余
    平均等待 151.76 秒,还有   0 打印任务剩余
    平均等待 122.95 秒,还有   0 打印任务剩余
    平均等待 119.68 秒,还有   0 打印任务剩余
    
    Process finished with exit code 0

    参考:https://www.bilibili.com/video/BV1QJ411w7bB?p=23

  • 相关阅读:
    docker pull配置代理方法
    docker配合ssh管道跨主机传输镜像
    Java面向对象详解
    云服务器的公网IP和内网IP的区别
    开启 kubectl 命令的自动补全功能
    Vue+Openlayers实现绘制线段并测量距离显示
    Vue+Openlayers+elradio实现切换地图显示
    koa使用swagger自动生成接口文档
    什么是低代码
    前后端统一接口的响应参数数据结构
  • 原文地址:https://www.cnblogs.com/yeshengCqupt/p/12590555.html
Copyright © 2011-2022 走看看