本文为学习笔记,感兴趣的读者可在MOOC中搜索《数据结构与算法Python版》或阅读《数据结构(C语言版)》(严蔚敏)
目录链接:https://blog.csdn.net/floating_heart/article/details/123991211
1.2.1 队列抽象数据类型及实现
队列是一种有次序的数据集合,其特征是:
-
新数据项的添加总发生在一端(通常称为“尾rear”端)
-
现存数据项的移除总发生在另一端(通常称为“首front”端)
当数据项加入队列,首先出现在队尾,随着队首数据项的移除,它逐渐接近队首。
这种次序安排的原则称为(FIFO:First-in first-out)先进先出
“队列”定义的操作:
**Queue():**创建一个空队列对象,返回值为Queue对象;
**enqueue(item):**将数据项item添加到队尾,无返回值;
**dequeue():**从队首移除数据项,返回值为队首数据项,队列被修改;
**isEmpty():**测试是否空队列,返回值为布尔值
**size():**返回队列中数据项的个数。
实现
代码:Python
class Queue:
def __init__(self):
self.item = []
def isEmpty(self):
return self.items == []
def enqueue(self,item):
self.item.insert(0,item)
def dequeue(self):
return self.item.pop()
def size(self):
return len(self.item)
代码:JavaScript-prototype
function Queue() {
this.item = []
}
Queue.prototype.isEmpty = function () {
return this.item.length == 0
}
Queue.prototype.enqueue = function (item) {
this.item.unshift(item)
}
Queue.prototype.dequeue = function () {
return this.item.pop()
}
Queue.prototype.size = function () {
return this.item.length
}
module.exports = { Queue }
代码:JavaScript-class
export default class Queue {
constructor() {
this.item = []
}
isEmpty() {
return this.item.length == 0
}
enqueue(item) {
this.item.unshift(item)
}
dequeue() {
return this.item.pop()
}
size() {
return this.item.length
}
}
1.2.2 热土豆问题(约瑟夫问题)
问题描述:
传说犹太人反叛罗马人,落到困境,约瑟夫和39人决定殉难,坐成一圈儿,报数1~7,报到7的人由旁边杀死
算法说明:
游戏时,队首始终是持有土豆的人
传递了num次后,将队首的人移除,不再入队如此反复,直到队列中剩余1人
实现:
代码:Python
from 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()
代码:JavaScript
import Queue from './Queue_c.js'
// const { Queue } = require('./Queue.js')
function hotPotato(namelist, num) {
let simqueue = new Queue()
for (let name of namelist) {
simqueue.enqueue(name)
}
while (simqueue.size() > 1) {
for (let i = 0; i < num; i++) {
simqueue.enqueue(simqueue.dequeue())
}
simqueue.dequeue()
}
return simqueue.dequeue()
}
1.2.3 打印任务
问题描述:
决策支持问题但无法通过规则直接计算:
多人共享一台打印机,采取“现到先服务”的队列策略来执行打印任务
一个具体的实例配置如下:
一个实验室,在任意的一个小时内,大约有10名学生在场,这一小时中,每人会发起2次左右的打印,每次1~20页
打印机的性能是:
以草稿模式打印的话,每分钟10页,以正常模式打印的话,打印质量好,但速度下降为每分钟5页。
问题是:
怎么设定打印机的模式,让大家都不会等太久的前提下尽量提高打印质量?
算法说明:
抽象问题,以时间为单位进行任务
对象:
**打印任务:**提交时间、打印页数
**打印队列:**具有FIFO性质的打印任务队列
**打印机:**打印速度、是否忙
过程:生成和提交打印任务
生成概率:每秒1/180
打印页数:1~20页
过程:实施打印
当前的打印作业:正在打印的作业
打印结束倒计时:新作业开始打印时开始倒计时,回0表示打印完毕,可以处理下一个作业
模拟时间:
统一的时间框架:以最小单位(秒)均匀流逝的时间,设定结束时间
同步所有过程:在一个时间单位里,对生成打印任务和实施打印两个过程各处理一次
模拟流程:
1.创建打印队列对象
2.时间按照秒的单位流逝
按照概率生成打印作业,加入打印队列;
如果打印机空闲,且队列不空,则取出队首作业打印,记录此作业等待时间;
如果打印机忙,则按照打印速度进行1秒打印;
如果当前作业打印完成,则打印机进入空闲
3.时间用尽,开始统计平均等待时间
获取作业等待时间:
生成作业时,记录生成的时间戳
开始打印时,当前时间减去生成时间即可
获取作业的打印时间:
生成作业时,记录作业的页数
开始打印时,页数除以打印速度即可
实现:
代码:Python
from Queue import Queue
import random
# 打印机对象
class Printer:
def __init__(self,ppm) -> None:
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
#任务对象 记录生成时间和页数
class Task:
def __init__(self,time) -> None:
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 == 1:
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,10)