python数据结构与算法分析--队列

本文参考于《python数据结构与算法分析》
队列:是有序集合,添加操作发生在尾部,移除操作发生在头部。新元素从尾部进入队列,然后一直向前移动到头部,直到成为下个被移除的元素。这种排序原则被称作FIFO(first-in-first-out),即先进先出。

队列抽象数据类型

  • Queue() 创建空队列
  • enqueue(item):尾部添加元素
  • dequeue():头部移除元素
  • isEmpty():检查是否为空
  • size():返回大小
class Queue:

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

    def enqueue(self, item):
        return self.items.insert(0, item)

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

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

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

模拟传土豆
这个游戏中孩子围城一圈,并依次尽可能快地传递一个土豆,如图:在某个时刻,大家停止传递,此时手里有土豆的孩子就得退出,重复上述过程直到只剩下一个孩子。
在这里插入图片描述

def hotPotato(namelist, num):
    
    simqueue = Queue()
    for name in namelist:
        simqueue.enqueue(name)
        
    while simqueue.size() > 1:
        for i in range(num):
            simqueue.printInfo()
            simqueue.enqueue(simqueue.dequeue())
            simqueue.printInfo()

            
        simqueue.dequeue()
    return simqueue.dequeue()

if __name__ == '__main__':
    result = hotPotato(["Bill", "David", "Susan", "Jane", "Kent", "Brad"], 7)
    print(result)
#结果:
['Brad', 'Kent', 'Jane', 'Susan', 'David', 'Bill']
['Bill', 'Brad', 'Kent', 'Jane', 'Susan', 'David']
['Bill', 'Brad', 'Kent', 'Jane', 'Susan', 'David']
['David', 'Bill', 'Brad', 'Kent', 'Jane', 'Susan']
['David', 'Bill', 'Brad', 'Kent', 'Jane', 'Susan']
['Susan', 'David', 'Bill', 'Brad', 'Kent', 'Jane']
['Susan', 'David', 'Bill', 'Brad', 'Kent', 'Jane']
['Jane', 'Susan', 'David', 'Bill', 'Brad', 'Kent']
['Jane', 'Susan', 'David', 'Bill', 'Brad', 'Kent']
['Kent', 'Jane', 'Susan', 'David', 'Bill', 'Brad']
['Kent', 'Jane', 'Susan', 'David', 'Bill', 'Brad']
['Brad', 'Kent', 'Jane', 'Susan', 'David', 'Bill']
['Brad', 'Kent', 'Jane', 'Susan', 'David', 'Bill']
['Bill', 'Brad', 'Kent', 'Jane', 'Susan', 'David']
['Bill', 'Brad', 'Kent', 'Jane', 'Susan']
['Susan', 'Bill', 'Brad', 'Kent', 'Jane']
['Susan', 'Bill', 'Brad', 'Kent', 'Jane']
['Jane', 'Susan', 'Bill', 'Brad', 'Kent']
['Jane', 'Susan', 'Bill', 'Brad', 'Kent']
['Kent', 'Jane', 'Susan', 'Bill', 'Brad']
['Kent', 'Jane', 'Susan', 'Bill', 'Brad']
['Brad', 'Kent', 'Jane', 'Susan', 'Bill']
['Brad', 'Kent', 'Jane', 'Susan', 'Bill']
['Bill', 'Brad', 'Kent', 'Jane', 'Susan']
['Bill', 'Brad', 'Kent', 'Jane', 'Susan']
['Susan', 'Bill', 'Brad', 'Kent', 'Jane']
['Susan', 'Bill', 'Brad', 'Kent', 'Jane']
['Jane', 'Susan', 'Bill', 'Brad', 'Kent']
['Jane', 'Susan', 'Bill', 'Brad']
['Brad', 'Jane', 'Susan', 'Bill']
['Brad', 'Jane', 'Susan', 'Bill']
['Bill', 'Brad', 'Jane', 'Susan']
['Bill', 'Brad', 'Jane', 'Susan']
['Susan', 'Bill', 'Brad', 'Jane']
['Susan', 'Bill', 'Brad', 'Jane']
['Jane', 'Susan', 'Bill', 'Brad']
['Jane', 'Susan', 'Bill', 'Brad']
['Brad', 'Jane', 'Susan', 'Bill']
['Brad', 'Jane', 'Susan', 'Bill']
['Bill', 'Brad', 'Jane', 'Susan']
['Bill', 'Brad', 'Jane', 'Susan']
['Susan', 'Bill', 'Brad', 'Jane']
['Susan', 'Bill', 'Brad']
['Brad', 'Susan', 'Bill']
['Brad', 'Susan', 'Bill']
['Bill', 'Brad', 'Susan']
['Bill', 'Brad', 'Susan']
['Susan', 'Bill', 'Brad']
['Susan', 'Bill', 'Brad']
['Brad', 'Susan', 'Bill']
['Brad', 'Susan', 'Bill']
['Bill', 'Brad', 'Susan']
['Bill', 'Brad', 'Susan']
['Susan', 'Bill', 'Brad']
['Susan', 'Bill', 'Brad']
['Brad', 'Susan', 'Bill']
['Brad', 'Susan']
['Susan', 'Brad']
['Susan', 'Brad']
['Brad', 'Susan']
['Brad', 'Susan']
['Susan', 'Brad']
['Susan', 'Brad']
['Brad', 'Susan']
['Brad', 'Susan']
['Susan', 'Brad']
['Susan', 'Brad']
['Brad', 'Susan']
['Brad', 'Susan']
['Susan', 'Brad']
Susan

打印机问题
在任何给定的一个小时内,实验室里都有约10个学生。他们在这一小时内最多打印2次,并且打印的椰树1-20不等。实验室的打印机比较老旧,每分钟只能以低质量打印10页。可以将打印质量提高,但是这样做会导致打印机每分钟只能打印5页。降低打印速度可能导致学生等待时间过长。那么如何设置打印速度?

在这里插入图片描述
模拟步骤:

在这里插入图片描述
实现:创建三个类: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.

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

打印任务模拟程序

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

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

#测试
for i in range(10):
    simulation(3600, 5)  #1小时   速度是5

for i in range(10):
    simulation(3600, 10) #1小时   速度10

#结果
Average Wait 292.59 secs   0 tasks remaining.
Average Wait  53.91 secs   0 tasks remaining.
Average Wait  13.69 secs   0 tasks remaining.
Average Wait  94.00 secs   2 tasks remaining.
Average Wait  41.27 secs   1 tasks remaining.
Average Wait 319.09 secs   6 tasks remaining.
Average Wait  98.04 secs   0 tasks remaining.
Average Wait  19.08 secs   1 tasks remaining.
Average Wait 104.05 secs   0 tasks remaining.
Average Wait  77.43 secs   0 tasks remaining.
------------------------------
Average Wait  17.50 secs   0 tasks remaining.
Average Wait  19.95 secs   0 tasks remaining.
Average Wait  44.45 secs   0 tasks remaining.
Average Wait  14.56 secs   0 tasks remaining.
Average Wait  12.14 secs   1 tasks remaining.
Average Wait  27.07 secs   0 tasks remaining.
Average Wait  28.68 secs   0 tasks remaining.
Average Wait  23.85 secs   0 tasks remaining.
Average Wait  13.18 secs   0 tasks remaining.
Average Wait  10.20 secs   0 tasks remaining.

双端队列
双端队列是与队列类似的有序集合。它有一前,一后两端,元素在其中保持自己的位置。与队列不同的是,双端队列对在哪一端添加和移除元素没有任何限制。新元素既可以被添加在前端,也可以被添加到后端。同理也可以从任意一端移除。
双端队列抽象数据类型

  • Deque():创建一个空的双端队列
  • addFront(item):将一个元素添加到双端队列的前端
  • addRear(item):将一个元素添加到双端队列的后端
  • removeFront():前端移除一个元素
  • removeRear():后端移除一个元素
  • isEmpty():检查是否为空
  • size():查看数目
class Deque:
    #假设列表尾部为前端
    def __init__(self):
        self.items = []
        
    def isEmpty(self):
        return self.items == []
    
    def addFront(self, item):
        return self.items.append(item)
    
    def addRear(self, item):
        return self.items.insert(0, item)
    
    def removeRear(self):
        return self.items.pop()
    
    def removeFront(self):
        return self.items.pop(0)
    
    def size(self):
        return len(self.items)

回文检测
回文是指从前往后读和从后往前读都一样的字符串,例如radar、toot等。
方案:使用一个双端队列来存储字符串中的字符。按从左往右的顺序将字符串中的字符添加到双端队列的后端。从前后两端移除元素,而且只有在二者相等时才继续。

def palchecker(aString):
    chardeque = Deque()

    for ch in aString:
        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("toot"))
print(palchecker("dfdfdfeqq"))
#结果
True
False
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值