本文参考于《python数据结构与算法分析》
队列:是有序集合,添加操作发生在尾部,移除操作发生在头部。新元素从尾部进入队列,然后一直向前移动到头部,直到成为下个被移除的元素。这种排序原则被称作FIFO(first-in-first-out),即先进先出。
队列抽象数据类型
- Queue() 创建空队列
- enqueue(item):尾部添加元素
- dequeue():头部移除元素
- isEmpty():检查是否为空
- size():返回大小
class Queue:
def __init__(self):
self.items = []
def enqueue(self, item):
return self.items.insert(0, item)
def dequeue(self):
return self.items.pop()
def size(self):
return len(self.items)
def isEmpty(self):
return self.items == []
模拟传土豆
这个游戏中孩子围城一圈,并依次尽可能快地传递一个土豆,如图:在某个时刻,大家停止传递,此时手里有土豆的孩子就得退出,重复上述过程直到只剩下一个孩子。
def hotPotato(namelist, num):
simqueue = Queue()
for name in namelist:
simqueue.enqueue(name)
while simqueue.size() > 1:
for i in range(num):
simqueue.printInfo()
simqueue.enqueue(simqueue.dequeue())
simqueue.printInfo()
simqueue.dequeue()
return simqueue.dequeue()
if __name__ == '__main__':
result = hotPotato(["Bill", "David", "Susan", "Jane", "Kent", "Brad"], 7)
print(result)
#结果:
['Brad', 'Kent', 'Jane', 'Susan', 'David', 'Bill']
['Bill', 'Brad', 'Kent', 'Jane', 'Susan', 'David']
['Bill', 'Brad', 'Kent', 'Jane', 'Susan', 'David']
['David', 'Bill', 'Brad', 'Kent', 'Jane', 'Susan']
['David', 'Bill', 'Brad', 'Kent', 'Jane', 'Susan']
['Susan', 'David', 'Bill', 'Brad', 'Kent', 'Jane']
['Susan', 'David', 'Bill', 'Brad', 'Kent', 'Jane']
['Jane', 'Susan', 'David', 'Bill', 'Brad', 'Kent']
['Jane', 'Susan', 'David', 'Bill', 'Brad', 'Kent']
['Kent', 'Jane', 'Susan', 'David', 'Bill', 'Brad']
['Kent', 'Jane', 'Susan', 'David', 'Bill', 'Brad']
['Brad', 'Kent', 'Jane', 'Susan', 'David', 'Bill']
['Brad', 'Kent', 'Jane', 'Susan', 'David', 'Bill']
['Bill', 'Brad', 'Kent', 'Jane', 'Susan', 'David']
['Bill', 'Brad', 'Kent', 'Jane', 'Susan']
['Susan', 'Bill', 'Brad', 'Kent', 'Jane']
['Susan', 'Bill', 'Brad', 'Kent', 'Jane']
['Jane', 'Susan', 'Bill', 'Brad', 'Kent']
['Jane', 'Susan', 'Bill', 'Brad', 'Kent']
['Kent', 'Jane', 'Susan', 'Bill', 'Brad']
['Kent', 'Jane', 'Susan', 'Bill', 'Brad']
['Brad', 'Kent', 'Jane', 'Susan', 'Bill']
['Brad', 'Kent', 'Jane', 'Susan', 'Bill']
['Bill', 'Brad', 'Kent', 'Jane', 'Susan']
['Bill', 'Brad', 'Kent', 'Jane', 'Susan']
['Susan', 'Bill', 'Brad', 'Kent', 'Jane']
['Susan', 'Bill', 'Brad', 'Kent', 'Jane']
['Jane', 'Susan', 'Bill', 'Brad', 'Kent']
['Jane', 'Susan', 'Bill', 'Brad']
['Brad', 'Jane', 'Susan', 'Bill']
['Brad', 'Jane', 'Susan', 'Bill']
['Bill', 'Brad', 'Jane', 'Susan']
['Bill', 'Brad', 'Jane', 'Susan']
['Susan', 'Bill', 'Brad', 'Jane']
['Susan', 'Bill', 'Brad', 'Jane']
['Jane', 'Susan', 'Bill', 'Brad']
['Jane', 'Susan', 'Bill', 'Brad']
['Brad', 'Jane', 'Susan', 'Bill']
['Brad', 'Jane', 'Susan', 'Bill']
['Bill', 'Brad', 'Jane', 'Susan']
['Bill', 'Brad', 'Jane', 'Susan']
['Susan', 'Bill', 'Brad', 'Jane']
['Susan', 'Bill', 'Brad']
['Brad', 'Susan', 'Bill']
['Brad', 'Susan', 'Bill']
['Bill', 'Brad', 'Susan']
['Bill', 'Brad', 'Susan']
['Susan', 'Bill', 'Brad']
['Susan', 'Bill', 'Brad']
['Brad', 'Susan', 'Bill']
['Brad', 'Susan', 'Bill']
['Bill', 'Brad', 'Susan']
['Bill', 'Brad', 'Susan']
['Susan', 'Bill', 'Brad']
['Susan', 'Bill', 'Brad']
['Brad', 'Susan', 'Bill']
['Brad', 'Susan']
['Susan', 'Brad']
['Susan', 'Brad']
['Brad', 'Susan']
['Brad', 'Susan']
['Susan', 'Brad']
['Susan', 'Brad']
['Brad', 'Susan']
['Brad', 'Susan']
['Susan', 'Brad']
['Susan', 'Brad']
['Brad', 'Susan']
['Brad', 'Susan']
['Susan', 'Brad']
Susan
打印机问题
在任何给定的一个小时内,实验室里都有约10个学生。他们在这一小时内最多打印2次,并且打印的椰树1-20不等。实验室的打印机比较老旧,每分钟只能以低质量打印10页。可以将打印质量提高,但是这样做会导致打印机每分钟只能打印5页。降低打印速度可能导致学生等待时间过长。那么如何设置打印速度?
模拟步骤:
实现:创建三个类:Printer、Task和PrintQueue。分别为模拟打印机、打印任务和队列。
Printer类需要检查当前是否有待完成的任务。如果有,那么打印机就处于工作状态,并且其工作所需的时间可以通过要打印的页数来计算。其构造方法会初始化打印速度,即每分钟打印多少页。tick方法会减量计时,并且执行完成任务后将打印机设置成空闲状态。
class Printer:
def __init__(self, ppm):
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
Task类代表单个打印任务。当任务被创建时,随机数生成器会随机提供页数,取值范围是1-20.
import random
class Task:
def __init__(self, time):
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 == 180:
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, 5) #1小时 速度是5
for i in range(10):
simulation(3600, 10) #1小时 速度10
#结果
Average Wait 292.59 secs 0 tasks remaining.
Average Wait 53.91 secs 0 tasks remaining.
Average Wait 13.69 secs 0 tasks remaining.
Average Wait 94.00 secs 2 tasks remaining.
Average Wait 41.27 secs 1 tasks remaining.
Average Wait 319.09 secs 6 tasks remaining.
Average Wait 98.04 secs 0 tasks remaining.
Average Wait 19.08 secs 1 tasks remaining.
Average Wait 104.05 secs 0 tasks remaining.
Average Wait 77.43 secs 0 tasks remaining.
------------------------------
Average Wait 17.50 secs 0 tasks remaining.
Average Wait 19.95 secs 0 tasks remaining.
Average Wait 44.45 secs 0 tasks remaining.
Average Wait 14.56 secs 0 tasks remaining.
Average Wait 12.14 secs 1 tasks remaining.
Average Wait 27.07 secs 0 tasks remaining.
Average Wait 28.68 secs 0 tasks remaining.
Average Wait 23.85 secs 0 tasks remaining.
Average Wait 13.18 secs 0 tasks remaining.
Average Wait 10.20 secs 0 tasks remaining.
双端队列
双端队列是与队列类似的有序集合。它有一前,一后两端,元素在其中保持自己的位置。与队列不同的是,双端队列对在哪一端添加和移除元素没有任何限制。新元素既可以被添加在前端,也可以被添加到后端。同理也可以从任意一端移除。
双端队列抽象数据类型
- Deque():创建一个空的双端队列
- addFront(item):将一个元素添加到双端队列的前端
- addRear(item):将一个元素添加到双端队列的后端
- removeFront():前端移除一个元素
- removeRear():后端移除一个元素
- isEmpty():检查是否为空
- size():查看数目
class Deque:
#假设列表尾部为前端
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def addFront(self, item):
return self.items.append(item)
def addRear(self, item):
return self.items.insert(0, item)
def removeRear(self):
return self.items.pop()
def removeFront(self):
return self.items.pop(0)
def size(self):
return len(self.items)
回文检测
回文是指从前往后读和从后往前读都一样的字符串,例如radar、toot等。
方案:使用一个双端队列来存储字符串中的字符。按从左往右的顺序将字符串中的字符添加到双端队列的后端。从前后两端移除元素,而且只有在二者相等时才继续。
def palchecker(aString):
chardeque = Deque()
for ch in aString:
chardeque.addRear(ch)
stillEqual = True
while chardeque.size() > 1 and stillEqual:
first = chardeque.removeFront()
last = chardeque.removeRear()
if first != last:
stillEqual = False
return stillEqual
#测试
print(palchecker("toot"))
print(palchecker("dfdfdfeqq"))
#结果
True
False