队列
栈是一种基于先进先出(FIFO)策略的集合类型,队列是日常现象的排队模型,进入队列的元素维持它们的原有顺序,并按照此顺序移出队列。
队列的基本操作
由此可以定义队列的基本操作:
- void enqueue(Item item)
- Item dequeue()
- boolean isEmpty()
- int size()
以上就是队列支持的所有操作,这是一个严格的接口说明书,没有额外的多余操作,这是一个良好的习惯,仅提供必需的接口,简洁而清晰(有些语言的库函数提供了Queue功能,但是却提供了额外的操作,比如可以在顶和底添加和删除元素)。
队列的实现
依照上述的接口说明书,我们可以通过各种结构来实现队列,最容易想到的就是上篇文章提到的线性存储结构,数组和链表。
数组实现
构造固定容量的一个数组, 记录队列的最大容量,并且维护两个指针first和last,用于记录队列头和队列尾,同时记录一个计数器n,记录当前队列中的元素个数。每次在数组的尾部进行添加元素则移动last指针,增加计数器;从队列头部取出元素则移动first指针,减少计数器。当last或者first移动到数组尾部则回绕到数组头部。当该队列固定容量数组达到上限,即数组已满,需要扩展数组容量(比如容量翻倍),把原来数据全部搬家到新数组,后续使用新数组继续操作。 随着数据的dequeue出队列,数据越来越少,数组空闲了很多空间,因此需要处理此种情况,当数据占用比例小于一定的数值,则需要重新申请一个小空间的数组,把数据搬家到此数组,把原来的大数组空间释放。
链表实现
使用前面文章描述的双循环链表,可以方便的实现队列所支持的操作。
初始状态,构造一个双循环链表,仅包含头节点。
void enqueue(Item item)
从双循环链表的尾部添加节点。Item dequeue()
从双循环链表的头部删除节点。boolean isEmpty()
判断头结点是否指向头结点。int size()
内部维护一个计数器,当enqueue时增加1,当dequeue时,减小1。
依靠双循环链表的通用结构,方便的实现队列,时间和空间复杂度为O(1),简洁而高效。
队列的应用
队列是一种常用的结构,如计算机科学中的生产者消费者问题,生产者生产数据放入队列尾部,消费者从队列头部取出数据处理。
源码参考
class LinkQueue(object):
'''使用双循环链表实现队列'''
def __init__(self):
self.__N = 0
self.__dlink = DoubleCircleList()
def enqueue(self, v):
self.__dlink.add_tail(v)
self.__N += 1
def dequeue(self):
if self.isEmpty():
raise Exception, "queue is empty when dequeue"
node = self.__dlink.del_head()
self.__N -= 1
return node.v
def peek(self):
if self.isEmpty() == 0:
raise Exception, "queue is empty when peek"
return self.__dlink.get_head().v
def isEmpty(self):
return self.__N == 0
def size(self):
return self.__N
def iterator(self):
return self.__dlink.iterator()