数据结构与算法(python版)之队列

一、什么是队列

1.队列

  队列是一种有次序的数据集合,其特征是新数据项的添加总发生在一端(通常称为“尾 rear”端),而现存数据项的移除总发生在另一端(通常称为“首front”端)。
  当数据项加入队列,首先出现在队尾,随着队首数据项的移除,它逐渐接近队首。
在这里插入图片描述

2.队列特征

  (1)先进先出或先到先服务;
  (2)队列只有一个入口和一个出口。
  (3)不允许数据项直接插入队中,也不允许从中间移除数据项。
在这里插入图片描述

3.队列的5个操作

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

4.示例

在这里插入图片描述

5.用list实现队列

  将list的首端作为队列尾端,list的末端作为队列首端,enqueue()的复杂度为O(n),dequeue()的复杂度为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)

二、队列的应用一:热土豆问题

1.问题描述

在这里插入图片描述

在这里插入图片描述

2.算法设计

  用队列来实现热土豆问题的算法,参加游戏人的列表,以及传土豆的次数num,算法返回最后剩下的人名。
在这里插入图片描述
在这里插入图片描述

3.实现程序

from pythonds.basic.queue 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(['A','B','C','D'],7))

三、队列的应用二:打印任务

1.任务

  多人共享一台打印机,采取先到先服务的队列策略来执行打印任务。在这种设定下,一个首要的问题是:
  (1)这种打印作业系统的容量有多大?
  (2)在能够接受的等待时间内,系统能容纳多少用户以多高频率提交多少任务。
  模拟算法:
在这里插入图片描述

2.问题

  怎么设定打印机的模式,让大家都不要等太久的前提下尽量提高打印质量。这是一个典型的决策支持问题,无法通过规则直接计算。我们用一段程序来模拟这种打印任务场景,然后对程序运行结果进行分析,支持我们对打印机模式设定的决策。

3.建模

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

3.模拟打印流程

在这里插入图片描述
在这里插入图片描述

4.实现程序

from pythonds.basic.queue import Queue
import random

class Printer:
    def __init__(self,ppm):
        #打印机速度
        self.pageRate=ppm
        #打印任务
        self.currentTask=None
        #任务倒计时
        self.timeRemaining=0

    #执行打印1s
    def tick(self):
        self.timeRemaining=self.timeRemaining-1
        if self.timeRemaining<=0:
            self.currentTask=None

    def isBusy(self):
        if self.currentTask!=None:
            return True
        else:
            return False

    #打印新作业
    def startNext(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 newPrintTask():
    # 1/180概率生成作业
    num=random.randrange(1,181)
    if num==180:
        return True
    else:
        return False

#仿真
#numSeconds:模拟时长
#pagePerMin:打印机速度
def simulation(numSeconds,pagePerMin):
    #创建打印机对象
    labPrinter=Printer(pagePerMin)
    #创建打印队列
    printQueue=Queue()
    #等待时间列表
    waitingTimes=[]
    for currentSecond in range(numSeconds):
        #是否有任务提交
        if newPrintTask():
            task=Task(currentSecond)
            printQueue.enqueue(task)
        # 如果打印机空闲且打印队列不空
        if (not labPrinter.isBusy()) 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()))

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

四、双端队列Deque

1.什么是双端队列Deque

  双端队列Deque是一种有次序的数据集,跟队列相似,其两端可称作“首”“尾”端,但Deque中的数据项既可以从队首加入,也可以从队尾端加入;数据项也可以从两端移除。
  从某种意义上说,双端队列集成了栈和队列的能力。
在这里插入图片描述

2.双端队列的7个操作

Deque() #创建一个空的双端队列
addFront(item) #将item加入队首
addRear(item) #将item加入队尾
removeFront() #从队首移除数据项,返回值为移除的数据项
removeRear() #从队尾移除数据项,返回值为移除的数据项
isEmpty() #返回Deque是否为空
size() #返回Deque中包含数据项的个数

3.实例

在这里插入图片描述

4.用List实现双端队列Deque

  将List的末端作为队首,将List的首端作为队尾。addFront()和removeFront()的复杂度为O(1),addRear()和removeRear()的复杂度为O(n).
  实现程序:

class Deque:
    def __init__(self):
        self.items = []

    def isEmpty(self):
        return self.items == []

    def addFront(self, item):
        self.items.append(item)

    def addRear(self, item):
        self.items.insert(0,item)

    def removeFront(self):
        return self.items.pop()

    def removeRear(self):
        return self.items.pop(0)

    def size(self):
        return len(self.items)

5.双端队列的一个应用:回文词的判断

  (1)什么是回文词?
  回文词指正读和反读一样的词。如:radar、madam、toot、上海自来水来自海上、山东落花生花落东山。
  (2)思路
    ①先将要判断的词从队尾加入Deque;
    ②从两端同时移除字符判断是否相同,直到Deque中的剩下0个或一个字符。

  (3)代码实现

from pythonds.basic.deque import Deque

def palchecker(aStr):
    charDeque=Deque()
    for ch in aStr:
        charDeque.addRear(ch)

    stillEqual=True
    while charDeque.size()>1 and stillEqual:
        first=charDeque.removeFront()
        last=charDeque.removeRear()
        if first!=last:
            stillEqual=False

    return stillEqual

print(palchecker('lsdkjfskf'))
print(palchecker('radar'))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值