队列

队列:

  • 特点:先进先出,有序集合,添加新项的一端为队尾,移除项的一端称为队首。
  • 排序原则为:FIFO,先进先出
  • 队列的抽象数据类型:
  • Queue() 创建一个空的新队列。它不需要参数,并返回一个空队列。
  • enqueue(item) 将新项添加到队尾。它需要item作为参数,并不返回任何内容。
  • dequeue() 从队首移除项。它不需要参数并返回item。队列被修改。
  • isEmpty() 查看队列是否为空。它不需要参数,并返回布尔值。
  • size() 返回队列中的项数。它不需要参数,并返回一个整数。
# -*- utf8 -*-
# Queue.py

'''
队列:
特点:先进先出,有序集合,添加新项的一端为队尾,移除项的一端称为队首。
排序原则为:FIFO,先进先出
队列的抽象数据类型:
Queue() 创建一个空的新队列。它不需要参数,并返回一个空队列。
enqueue(item) 将新项添加到队尾。它需要item作为参数,并不返回任何内容。
dequeue() 从队首移除项。它不需要参数并返回item。队列被修改。
isEmpty() 查看队列是否为空。它不需要参数,并返回布尔值。
size() 返回队列中的项数。它不需要参数,并返回一个整数。
'''

'''
用python实现一个Queue
实现一个Queue类,底层使用列表集合作为构建队列的内部表示
假定队尾在列表中的位置为0,使用列表的插入函数向队列添加新元素,弹出可用于删除队首的元素(列表的最后一个元素)
入队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()
q.enqueue(4)
q.enqueue(5)
print(q.size())
print(q.isEmpty())
q.enqueue(8.4)
print(q.dequeue())
print(q.size())

# 2
# False
# 4
# 2


image.png
'''
队列的实际应用,烫手山芋
游戏规则:孩子们围成一个圈,并尽可能快的将一个山芋递给旁边的孩子。在某一个时间,
动作结束,有山芋的孩子从圈中移除,游戏继续直到剩下最后一个孩子。

模拟这个游戏的过程的大概思路:使用队列来模拟这个圈,先假设所有的孩子都在队列里,拿着山芋的孩子在队列的前面,当拿到山芋的时候,
这个孩子将先出列,再把他放到队列的最后。然后山芋又回到队列前的孩子,继续重复刚才的操作。但是我们先得给定一个num,表示经过第num次的
出队入队后,前面的孩子将被永久移除队列。直到最后只剩下一个孩子(队列大小为1).

注意:num要大于列表中的名称数,因为队列像一个圈,计数会重新回到开始,直到达到计数值。
'''

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

image.png
'''
队列的实际应用:模拟打印机

规则,一台共享打印机,10个同学排队打印,计算平均的等待时间。

模拟主要步骤:
 1、创建打印任务的队列,每个任务都有个时间戳(任务从创建到入队的时间)。队列启动的时候为空。
 2、每秒(currentSecond)
    - 是否创建新的打印任务?如果是,将currentSecond(任务加入队列的时间)作为时间戳添加到队列。
    - 如果打印机不忙并且有任务在等待
      - 从打印机队列中删除一个任务并将其分配给打印机
      - 从currentSecond中减去时间戳,以计算该任务的等待时间。(也就是任务从进入到队列到开始打印之间的等待时间)
      - 将该任务的等待时间附件到列表中稍后处理。    
    - 打印机需要一秒打印,所以得从该任务的所需的等待时间减去一秒。 (从给定的numSecond开始倒数,并且倒数一秒就代表打印了一秒)
    - 如果任务已经完成,换句话说,所需的时间已经达到零,打印机空闲。
3、模拟完成后,从生成的等待时间列表中计算平均等待时间。
'''

'''
创建三个类:Printer, Task, PrintQueue
Printer,打印机类。
- 需要跟踪它当前是否有任务,如果有则它处于busy状态
- 可以从任务的页数计算所需的时间。
- 构造函数允许初始化每分钟页面的配置
- 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              # 因为timeRemaining是秒,而pagerat是每分钟打印的页数



'''
Task, 任务类。
- 创建任务时,随机数生成器将提供1到20页的长度。使用随机模块中randrange函数
- 每个任务保存一个时间戳用于计算等待时间。此时间戳表示任务被创建并放到打印机队列的时间。
- waitTime方法检索在打印开始之前队列中花费的时间。
'''
import random

class Task:
    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



'''
PrintQueue :等待队列类,上面已经实现
simulation:模拟打印方法
newPrintTask: 决定是否创建新的打印任务,打印任务每180秒我们就创建一个新的。
'''

import random

def simulation(numSeconds, pagePerMinute):                                  # numSeconds为打印机会运行的总时间

    labprinter = Printer(pagePerMinute)                                     # 打印机传入每分钟打印的页数
    printQueue = Queue()
    waitingtimes = []                                                       # 等待时间列表

    for currentSecond in range(numSeconds):

        if newPrintTask():                                                  # 3分钟就会有一个打印任务生成
            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()                                                   # 计时器,numSeconds之后开始倒计时

    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


# 每分钟5页,运行60分钟
for i in range(10):
    simulation(3600,5)


# Average Wait  38.60 secs   1 tasks remaining.
# Average Wait  76.05 secs   2 tasks remaining.
# Average Wait  55.87 secs   3 tasks remaining.
# Average Wait  79.60 secs   0 tasks remaining.
# Average Wait  76.12 secs   0 tasks remaining.
# Average Wait  90.53 secs   0 tasks remaining.
# Average Wait  98.25 secs   1 tasks remaining.
# Average Wait  48.13 secs   0 tasks remaining.
# Average Wait  87.52 secs   0 tasks remaining.
# Average Wait 262.91 secs   3 tasks remaining.
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容