数据结构与算法(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

posted @ 2020-03-29 01:09  Yelush  阅读(283)  评论(0编辑  收藏  举报