python 队列

       队列(queue)在计算机科学中,是一种先进先出的线性表。它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。

       队列抽象数据类型由以下结构和操作定义。如上所述,队列被构造为在队尾添加项的有序集合,并且从队首移除。队列保持 FIFO 排序属性。 队列操作如下:

  • Queue() 创建一个空的新队列。 它不需要参数,并返回一个空队列。
  • enqueue(item) 将新项添加到队尾。 它需要 item 作为参数,并不返回任何内容。
  • dequeue() 从队首移除项。它不需要参数并返回 item。 队列被修改。
  • isEmpty() 查看队列是否为空。它不需要参数,并返回布尔值。
  • size() 返回队列中的项数。它不需要参数,并返回一个整数。

       如下表所示,我们假设 q 是已经创建并且当前为空的队列,则下表展示了队列操作序列的结果。右边表示队首。 4 是第一个入队的项,因此它dequeue 返回的第一个项。

实现队列抽象数据类型创建一个新类,使用列表集合来作为构建队列的内部表示。假定队尾在列表中的位置为 0。这允许我们使用列表上的插入函数向队尾添加新元素。弹出操作可用于删除队首的元素(列表的最后一个元素)。代码如下:

       实现队列抽象数据类型创建一个新类,使用列表集合来作为构建队列的内部表示。假定队尾在列表中的位置为 0。这允许我们使用列表上的插入函数向队尾添加新元素。弹出操作可用于删除队首的元素(列表的最后一个元素)。代码如下:

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)

一、超市排队时长问题 

codeWars中的题目:

There is a queue for the self-checkout tills at the supermarket. Your task is write a function to calculate the total time required for all the customers to check out!

The function has two input variables:

  • customers: an array (list in python) of positive integers representing the queue. Each integer represents a customer, and its value is the amount of time they require to check out.
  • n: a positive integer, the number of checkout tills.

The function should return an integer, the total time required.

EDIT: A lot of people have been confused in the comments. To try to prevent any more confusion:

  • There is only ONE queue, and
  • The order of the queue NEVER changes, and
  • Assume that the front person in the queue (i.e. the first element in the array/list) proceeds to a till as soon as it becomes free.
  • The diagram on the wiki page I linked to at the bottom of the description may be useful.

So, for example:

queue_time([5,3,4], 1)
# should return 12
# because when n=1, the total time is just the sum of the times

queue_time([10,2,3,3], 2)
# should return 10
# because here n=2 and the 2nd, 3rd, and 4th people in the 
# queue finish before the 1st person has finished.

queue_time([2,3,10], 2)
# should return 12

       这道题是经典的超市购物排队问题:有一个队列 customers[],队列中每个元素是当前顾客的处理时长,有 n 个购物台,可以同时处理n个客户。这是题目大意,求的是队列的处理时长。
特别注意:

  • 只有一个队列,
  • 队列处理顺序不能变,
  • 假设队列中的前面的人(即数组/列表中的第一个元素)在有购物台空闲的时候就会继续前进。
def queue_time(customers, n):
    list_temp = [0]*n
    for item in customers:
        list_temp[list_temp.index(min(list_temp))] += item
    return max(list_temp)

二、烫手的山芋

问题描述

游戏烫手山芋,在这个游戏中,孩子们围成一个圈,并尽可能快的将一个山芋递给旁边的孩子。在某一个时间,动作结束,有山芋的孩子从圈中移除。游戏继续开始直到剩下最后一个孩子。

解题思路

为了模拟这个圈,我们使用队列(见下图)。假设拿着山芋的孩子在队列的前面。当拿到山芋的时候,这个孩子将先出列再入队列,把他放在队列的最后。经过 num 次的出队入队后,前面的孩子将被永久移除队列。并且另一个周期开始,继续此过程,直到只剩下一个名字(队列的大小为 1)

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

三、用队列实现对打印机使用情况的模拟

问题描述

假设实验室里有一台打印机供学生共享。当学生向共享打印机发送打印任务时,任务被放置在队列中以便以先来先服务的方式被处理。如何才能通过python程序模拟的方式得到每次提交任务的平均等待时间呢?(平均等待时间不包括打印本身的时间,仅指在队列中排队的时间。)
我们假定:

  1. 学生们每次打印的页数在1到20页之间。
  2. 打印机平均每小时会收到20个打印请求,即平均每180秒1个请求。
  3. 每秒新增任务的可能性相等,即任务的产生为独立同分布
  4. 打印机的打印速度恒定。

总体模拟思路

当学生提交打印任务时,我们将把他们添加到打印任务的等待队列。当打印机完成任务时,它将检查队列,将剩余的任务中队首的那一个弹出并处理。学生等待他们的任务打印的平均时间也等于任务在队列中等待的平均时间。
我们将对每个任务入队和出队的时间戳进行记录,由此得到该任务在队列中的等待时间。

对任务的模拟

任务类应包括以下几个功能:随机生成页数、记录入队时间戳、返回需要打印的页数、根据当前时间戳返回等待的时间。

class Task:
    #任务初始化
    def __init__(self, time):
        # time 为传入的任务创建时间,也就是入队时间
        self.in_time = time
        self.pages = random.randrange(1,21) # 随机生成1到20页之间的页数
    
    #返回任务需要打印的页数
    def getPage(self):
        return self.pages
    
    def waitTime(self, out_time):
        # out_time为当前时间戳
        return out_time - self.in_time

对打印机的模拟

打印机类应包括以下几个功能:设定打印速度(多少秒每页)、载入新任务并计算新任务剩余打印时间、记录当前任务的剩余打印时间、打印(即减少已载入任务的剩余打印时间)。

class Printer:
    #打印机初始化
    def __init__(self, timeperpage):
        #timeperpage 为每页打印所需要的时间,设定好后便是恒定的值
        self.timeperpage = timeperpage
        self.current_task = None #记录当前正在处理的任务
        self.remaining_time = 0 #记录当前任务的剩余处理时间
    
    #返回打印机中是否有任务
    def isBusy(self):
        return self.current_task != None
    
    #载入新的任务
    def loadTask(self, next_task):
        # next_task 为新的任务
        self.current_task = next_task
        self.remaining_time = next_task.getPage()*self.timeperpage #计算新的剩余打印时间
    
    #打印
    def printTask(self):
        if self.isBusy(): #有任务需要处理
            self.remaining_time -= 1 # 打印,也就是将剩余打印时间减一
            if self.remaining_time <= 0: # 当前任务打印结束
                self.current_task = None
        else: #空闲中
            pass

借助队列模拟打印情况,并计算平均等待时间

由于任务的产生为独立同分布,我们可以在每一秒上运行1到180间随机数生成,当值为1时产生新任务请求,以模拟每180秒一个新任务的任务产生速度。

def simulation(total_time, timeperpage):
    # total_time为总的实验时间,timeperpage为每页打印所需要的时间
    waiting_time = [] #记录每个任务的等待时间
    
    printer = Printer(timeperpage) #初始化打印机
    waitQueue = Queue() #初始化任务等待队列
    
    for second in range(total_time):
        
        rand_num = random.randrange(1,181) #产生1到180之间的随机数
        if rand_num == 1:
            new_task = Task(second) #产生新任务
            waitQueue.enqueue(new_task) #新任务进入等待队列
            
        if (not printer.isBusy()) and (not waitQueue.isEmpty()): #打印机空闲并且有任务在等待
            next_task = waitQueue.dequeue() # 弹出下一个任务
            waiting_time.append(new_task.waitTime(second)) # 计算并记录等待时间
            printer.loadTask(next_task) #载入新的任务
        
        printer.printTask() #打印
    
    average_time = sum(waiting_time)/len(waiting_time)
    return average_time

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值