小言_互联网的博客

Python数据结构与算法2 队列的实现与应用

292人阅读  评论(0)

什么是队列?

队列是一种有次序的数据集合,其特征是新数据项的添加总发生在一端(通常称为"尾rear端",而现存数据项的另一端的移除总发生在另一端(通常称为"首front"端。当数据项加入队列,首先出现在队尾,随着队首数据项的移除,它逐渐接近队首
新加入的数据项必须在数据集末尾等待,而等待时间最长的数据项则是队首,这种次序安排的原则成为(FIFO:First-in-first-out)先进先出
队列的例子出现在我们日常生活的方方面面:排队

队列仅有一个入口和一个出口

抽象数据类型Queue

Queue():创建一个空队列对象,返回Queue对象;
enqueue(item):将数据项item添加到队尾,无返回值;
dequeue():从队首移除数据项,返回值为队首数据项,队列被修改
isEmpty():测试是否空队列,返回值为布尔值
size():返回队列中数据项的个数
peek():查看队列最早的元素

实现:

class Queue:
    def __init__(self):
        self.items = []
    def enqueue(self,item):
        return self.items.append(item)
    def dequeue(self,):
        return self.items.pop(0)
    def isEmpty(self):
        return len(self.items)==0
    def size(self):
        return len(self.items)
    def peek(self):
        return self.items[0]

队列的应用
热土豆问题(约瑟夫问题)
传说犹太人反叛罗马人,落到困境,约瑟夫和39人决定殉难,坐成一圈儿,报数1~7,报到7的人由旁边杀死,结果约瑟夫给自己安排了个位置,最后活了下来。
算法流程:

  • 模拟程序采用队列来存放所有参加游戏的人名,按照传递土豆的方向从队首排到队尾,游戏时,队首始终是持有土豆的人
  • 模拟游戏开始,只需要将队首的人出队,随机再到队尾入队,算是土豆的一次传递,传递到num次后,将队首的人移除,不再入队如此反复,直到队列中剩余一人
def hotpotato(namelist,num):#放名字的列表,num为数到几出列
    q = Queue()
    for name in namelist:
        q.enqueue(name)
    while q.size()>1:
        for i in range(num):
            q.enqueue(q.dequeue())

        q.dequeue()
    return q.dequeue()

print(hotpotato(['江苏','北京','南京','上海'],4))

队列的应用2 模拟打印任务
一台计算机可能连着一台打印机,有些打印机连在局部网络上,用户可以通过网络把文件送去打印。
由于打印机速度有限,用户的使用需求也会有各种变化,有可能出现这样的情况:当打印机正在工作,打印一个文件的过程中,又有用户通过某些方式送来一个或几个需要打印的文件,对于多台机器共享的网络打印机,经常会出现接受到一些打印任务,但却由于正在工作不能立即楚处理它们的情况。在这些情况中,待打印文件都需要缓存。
打印机的管理程序(可能出现在不同层次)管理着一个缓存打印任务的队列。接到新任务时,如果打印机正在忙,管理程序就将该任务放入队列。一旦打印机完成了当前工作,管理程序就查看队列,取出其中最早的任务送给打印机。

**模拟流程:

  • 一个实验室任意一小时内,大约有10名学生在.在这一个小时中,每个人会发起2次左右的打印,每次1-20页
    打印机:以草稿模式打印:每分钟10页,正常模式,每分钟5页
    问题是:怎么设定打印机的模式,让大家都不会等太久的前提下尽量提高打印机质量
    这是一个典型的决策支持问题,但无法通过规则直接进行计算
    我们要用一段程序来模拟这种打印任务场景,然后对程序运行结果进行分析,以支持对打印机模式设定的决策

首先对问题进行建模

  • 1对象:打印任务 打印队列 打印机
    打印任务属性:提交时间 打印页数
    打印队列属性: 具有FIFO性质的打印任务队列(first input first output)
    打印机属性:打印速度 是否忙

  • 2过程:生成和提交打印任务
    确定生成概率:实例为每小时会有10个学生提交的20个作业,这样,概率是每180秒会有1个作业生成并提交,概率为每秒1/180
    确定打印页数:实例是1-20页,那么就是1-20页之间的概率相同

  • 3过程:实施打印
    当前的打印作业:正在打印的作业
    打印结束倒计时:新作业开始打印时开始倒计时,回0表示打印完毕,可以处理下一个作业

  • 4模拟时间:
    统一的时间框架:以最小单位(秒)均匀流逝的时间,设定结束时间
    同步所有过程:在一个单位时间里,对生成打印任务和实施打印两个过程各处理一次

打印任务:模拟流程
1创建打印队列对象
2时间按照秒的单位流逝
按照概率生成打印作业,加入打印队列
如果打印机空闲,且队列不空,则取出队首作业打印记录此作业等待时间
如果打印机忙,则按照打印速度进行1秒打印
如果当前作业打印完成,则打印机进入空闲
3时间用尽,开始统计平均等待时间
作业的等待时间:
生成作业时,记录生成的时间戳
开始打印时,当前时间减去生成时间即可
作业的打印时间
生成作业时,记录作业的页数
开始打印时,页数除以打印速度即可

**

mport random
#打印机属性:打印速度 是否忙
class Printer:

    def __init__(self,ppm):
        self.pagerate=ppm#打印速度
        self.current_task=None#打印任务
        self.time_remaining=0#倒计时

    def tick(self):#打印1秒.有任务时,打印结束倒计时-1.当倒计时为0,打印完成
        if self.current_task != None:
            self.time_remaining = self.time_remaining -1
            if self.time_remaining <= 0:
                self.current_task = None

    def busy(self):#是否忙
        if self.current_task != None:
            return True
        else:
            return False
    def start_next(self,new_task):#打印新作业
        self.current_task=new_task
        self.time_remaining=new_task.getPages()*self.pagerate

class Task:
    #打印任务属性:提交时间 打印页数
    def __init__(self,time):
        self.timestamp = time#生成时间戳
        self.pages = random.randrange(1,21)#实例是1-20页,那么就是1-20页之间的概率相同
    def getStamp(self):
        return self.timestamp
    def getPages(self):
        return self.pages
    def waitTime(self,current_time):
        return current_time - self.timestamp    #等待时间:
                                                # 生成作业时,记录生成的时间戳
                                                # 开始打印时,当前时间减去生成时间即可

def newPrintTask():#概率是每180秒会有1个作业生成并提交,概率为每秒1/180.所以生成新任务的概率是1/180
    num = random.randrange(1,181)
    if num == 180:
        return True
    else:
        return False

def simulation(num_second,page_perminute):
    labprinter = Printer(page_perminute)
    print_queue=Queue()
    waitingtimes=[]
    for currentSecond in range(num_second):
        if newPrintTask():
            task = Task(currentSecond)
            print_queue.enqueue(task)
        if(not labprinter.busy()) and (not print_queue.isEmpty()):
            nexttask = print_queue.dequeue()
            waitingtimes.append(nexttask.waitTime(currentSecond))
        labprinter.tick()
    averageWait = sum(waitingtimes)/len(waitingtimes)
    print('Average Wait %6.2f secs %3d tasks remaining.'%(averageWait,print_queue.size()))

for i in range(10):
    simulation(3600,1)
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


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,waitQueue.size()
def main():
    timeperpage = 6#打一页所需时间
    total_time = 36000 #10小时
    print("-----------------")
    for i in range(10):
        average_time,wait_ = simulation(total_time,timeperpage)
        print("平均等待打印时间为:%.5f 秒"%average_time)
        print('剩余等待%3d'%(wait_))
        print("-----------------")

if __name__ == "__main__":
    main()

转载:https://blog.csdn.net/rhythmcc/article/details/105435758
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场