数据结构与算法(基本数据结构-队列)
一、队列概述
概念:队列是项的有序结合,其中添加新项的一端称为队尾,移除项的一端称为队首。当一个元素从队尾进入队列时,一直向队首移动,直到它成为下一个需要移除的元素为止。最近添加的元素必须在队尾等待。集合中存活时间最长的元素在队首,这种排序成为 FIFO,先进先出,也被成为先到先得。
案例:队列的最简单的例子是我们平时不时会参与的列。排队等待电影,在杂货店的收营台等待,在自助餐厅排队等待(这样我们可以弹出托盘栈)。行为良好的线或队列是有限制的,因为它只有一条路,只有一条出路。不能插队,也不能离开。你只有等待了一定的时间才能到前面。
队列的应用:我们的计算机实验室有 30 台计算机与一台打印机联网。当学生想要打印时,他们的打印任务与正在等待的所有其他打印任务“一致”。第一个进入的任务是先完成。如果你是最后一个,你必须等待你前面的所有其他任务打印。我们将在后面更详细地探讨这个有趣的例子。
除了打印队列,操作系统使用多个不同的队列来控制计算机内的进程。下一步做什么的调度通常基于尽可能快地执行程序和尽可能多的服务用户的排队算法。此外,当我们敲击键盘时,有时屏幕上出现的字符会延迟。这是由于计算机在那一刻做其他工作。按键的内容被放置在类似队列的缓冲器中,使得它们最终可以以正确的顺序显示在屏幕上。
二、Python实现队列
队列的抽象数据类型应该由以下结构和操作定义。队列操作如下:
-
- Queue() 创建一个空的新队列。 它不需要参数,并返回一个空队列。
- enqueue(item) 将新项添加到队尾。 它需要 item 作为参数,并不返回任何内容。
- dequeue() 从队首移除项。它不需要参数并返回 item。 队列被修改。
- isEmpty() 查看队列是否为空。它不需要参数,并返回布尔值。
- size() 返回队列中的项数。它不需要参数,并返回一个整数。
# 创建一个队列 class Queue(): def __init__(self): self.items = [] # 队列插入元素(左端) def enqueue(self,item): self.items.insert(0,item) # 队列删除元素(右端) def dequeue(self): return self.items.pop() # 判断队列是否为空,空返回True,否则返回False def isEmpty(self): return self.items == [] # 返回队列长度 def size(self): return len(self.items)
队列测试:
>>> q.size() 3 >>> q.isEmpty() False >>> q.enqueue(8.4) >>> q.dequeue() 4 >>> q.dequeue() 'dog' >>> q.size() 2
三、队列的应用实例(烫手的山芋)
实验规则:烫手山芋游戏介绍:6个孩子围城一个圈,排列顺序孩子们自己指定。第一个孩子手里有一个烫手的山芋,需要在计时器计时1秒后将山芋传递给下一个孩子,依次类推。规则是,在计时器每计时7秒时,手里有山芋的孩子退出游戏。该游戏直到剩下一个孩子时结束,最后剩下的孩子获胜。请使用队列实现该游戏策略,排在第几个位置最终会获胜。
分析:
- 为了模拟这个圈,我们可以使用队列。假设游戏开始时,排在队列中的第一个(队首)的孩子手里拿着山芋。游戏开始后,拿着山芋的孩子出队列然后再入队列,将山芋传递给下一个孩子。每当山芋到队首孩子手里后,队首的孩子先出队列再入队列,依次类推。当传递六次后,手里有山芋的孩子淘汰,游戏继续,继续传递山芋。
- 手里有山芋的孩子淘汰后,队列指针指向下一个孩子,保证手里有山芋的孩子永远站在队列的头部
代码实现:
q = Queue() kids = ['A','B','C','D','E','F'] # 进队列(循环队列) for kid in kids: q.enqueue(kid) # 队列中剩最后一个孩子则跳出循环,孩子获胜 while q.size() > 1: # 内层循环是用来将手里有山芋的孩子排在队头 # 每次计时器到时,删除当前孩子,则指针指向的下一个孩子位置 # 每次计时,循环队列 for i in range(6): # 删除队列最后一个孩子 kid = q.dequeue() # 删除的孩子重新添加在队首位置,实现队列循环 q.enqueue(kid) # 6s计时到时,删除最后一个孩子,指针指向下一个孩子 q.dequeue() # 打印最后获胜的孩子 print(q.dequeue()) # 孩子E获胜,留下的最后一个孩子 # 结果>>>E