队列的典型应用之一是模拟需要以 FIFO 方式管理数据的真实场景。首先,让我们看看孩子们的游戏烫手山芋,在这个游戏中(见 Figure 2),孩子们围成一个圈,并尽可能快的将一个山芋递给旁边的孩子。在某一个时间,动作结束,有山芋的孩子从圈中移除。游戏继续开始直到剩下最后一个孩子。
Figure 2 模拟:烫手山芋
这个游戏相当于著名的约瑟夫问题,一个一世纪著名历史学家弗拉维奥·约瑟夫斯的传奇故事。故事讲的是,他和他的 39 个战友被罗马军队包围在洞中。他们决定宁愿死,也不成为罗马人的奴隶。他们围成一个圈,其中一人被指定为第一个人,顺时针报数到第七人,就将他杀死。约瑟夫斯是一个成功的数学家,他立即想出了应该坐到哪才能成为最后一人。最后,他加入了罗马的一方,而不是杀了自己。
我们将模拟这个烫山芋的过程。我们的程序将输入名称列表和一个称为 num 常量用于报数。它将返回以 num
为单位重复报数后剩余的最后一个人的姓名。
为了模拟这个圈,我们使用队列(见 Figure3)。假设拿着山芋的孩子在队列的前面。当拿到山芋的时候,这个孩子将先出列再入队列,把他放在队列的最后。经过 num 次的出队入队后,前面的孩子将被永久移除队列。并且另一个周期开始,继续此过程,直到只剩下一个名字(队列的大小为 1)。
Figure 3 模拟:烫手山芋
class Queue:
def __init__(self):
self.duilie = []
def isempty(self):
if len(self.duilie) == 0:
return True
else:
return False
def enqueue(self, items):
return self.duilie.insert(0, items)
def dequeue(self):
return self.duilie.pop()
def size(self):
return len(self.duilie)
name = ['Brad', 'kent', 'jane', 'susan', 'david', 'bill']
queue = Queue()
# 入队操作
for item in name:
queue.enqueue(item)
num = input()
for i in range(1, 100):
if queue.size() == 1:
b = queue.dequeue()
print(b)
break
if i % num != 0:
a = queue.dequeue()
queue.enqueue(a)
if i % num == 0:
c = queue.dequeue()
Deque
deque(也称为双端队列)是与队列类似的项的有序集合。它有两个端部,首部和尾部,并且项在集合中保持不变。deque 不同的地方是添加和删除项是非限制性的。可以在前面或后面添加新项。同样,可以从任一端移除现有项。在某种意义上,这种混合线性结构提供了单个数据结构中的栈和队列的所有能力。 Figure 1 展示了一个 Python 数据对象的 deque 。
要注意,即使 deque 可以拥有栈和队列的许多特性,它不需要由那些数据结构强制的 LIFO 和 FIFO 排序。这取决于你如何持续添加和删除操作。
# 双端队列
class Deque:
def __init__(self):
self.duilie = []
def isempty(self):
if len(self.duilie) == 0:
return True
else:
return False
def addfront(self, items):
self.duilie = self.duile.append(items)
def addrear(self, items):
self.duilie = self.duilie.insert(0, items)
def removefront(self):
self.duilie = self.duilie.pop(0)
def removerear(self):
self.duilie = self.duilie.pop()
def size(self):
return len(self.duilie)