队列中的元素都是先进先出(First In First Out, FIFO)
上溢:当队列满时,入队时产生的溢出现象。
下溢:当队列空时,出队时产生的溢出现象。
用列表来实现队列存在着一定的困难。首先根据队列的定义,出队应该在表首进行,但是一个元素出队后,需要将后面的元素依次前移一位,这是一个O(n)时间的操作。Python中list对象的pop(0)就是这样。
另一种可能是在队首元素出队后,剩余的元素不前移,但要记住队头所在的新的位置。但是这样会让前面空出来的存储空间无法再次利用。基于此,可以将列表看做是一个环形的结构。这样可以将前面空出来的存储区域进行再次利用。
class QueueUnderflow(ValueError): pass class SQueue(): def __init__(self, init_len=8): self.len = init_len # 存储区长度 self.elems = [0] * init_len # 元素存储 self.head = 0 # 表头元素下标 self.num = 0 # 元素个数 def is_empty(self): return self.num == 0 def peek(self): # 查看队列中最早进入的元素,但不删除 if self.num == 0: raise QueueUnderflow return self.elems[self.head] def dequeue(self): # 删除队列中最早进入的元素,并将其返回,即出队 if self.num == 0: raise QueueUnderflow val = self.elems[self.head] self.head = (self.head + 1) % self.len self.num -= 1 return val def enqueue(self, val): # 在队列的末尾加入元素,即入队 if self.num == self.len: self.extend() self.elems[(self.head + self.num) % self.len] = val self.num += 1 def extend(self): old_len = self.len self.len *= 2 new_elems = [0] * self.len for i in range(old_len): new_elems[i] = self.elems[(self.head + i) % old_len] self.elems, self.head = new_elems, 0 if __name__ == '__main__': sq = SQueue() sq.enqueue('a') sq.enqueue('b') print(sq.dequeue())
Python中的四种队列:
from queue import Queue #先进先出FIFO队列 q = Queue() #创建队列对象 for i in range(6): #在队列尾部插入元素 q.put(i) print(q.queue) #查看队列中的所有元素 #输出:deque([0, 1, 2, 3, 4, 5]) print(q.get()) #返回并删除队列头部元素 print(q.queue) #输出:deque([1, 2, 3, 4, 5]) from queue import LifoQueue #后进先出LIFO队列 lifoQueue = LifoQueue() for i in range(6): #在队列尾部插入元素 lifoQueue.put(i) print(lifoQueue.queue) #输出:deque([0, 1, 2, 3, 4, 5]) lifoQueue.get() #返回并删除队列尾部元素 print(lifoQueue.queue) #输出:deque([0, 1, 2, 3, 4]) from queue import PriorityQueue #优先队列 p = PriorityQueue() for i in range(2): #在队列尾部插入元素 p.put(i) p.put(78) p.put(3) print(p.queue) #输出:[0, 1, 78, 3] print(p.get()) #返回并删除优先级最高的元素 #输出:0 print(p.get()) #输出:1 print(p.get()) #输出:3 print(p.get()) #输出:78 from collections import deque #双端队列 d = deque(range(3)) d.append(6) #在右侧插入新元素 print(d) #输出:deque([0, 1, 2, 6]) d.appendleft(8) #在左侧插入新元素 print(d) #输出:deque([8, 0, 1, 2, 6]) d.rotate(2) #循环右移2次 print(d) #输出:deque([2, 6, 8, 0, 1]) d.popleft() #返回并删除队列最左端元素 print(d) #输出:deque([6, 8, 0, 1]) d.pop() #返回并删除队列最右端元素 print(d) #输出:deque([6, 8, 0])