8.1 队列ADT
队列(queue):只能在一端插入元素,在另一端删除元素的容器。其特点是先进先出(first-in first-out, FIFO)。
插入元素的一端称为后端(back),也称为队尾,删除元素德一端称为前端(front),也称为队头。
其具有如下属性:
- Queue():创建空队列;
- isEmpty():判断当前队列是否为空;
- length():返回队列长度;
- enqueue():添加元素到队尾;
- dequeue():从队头删除元素。
有三种方式可以实现队列,分别是python列表、数组以及链表。
基于python列表的实现
这种方式最简单。
#-*-coding: utf-8-*-
# 使用python列表实现队列
class Queue(object):
def __init__(self):
self._qList = list()
def isEmpty(self):
return len(self) == 0
def __len__(self):
return len(self._qList)
def enqueue(self, item):
self._qList.append(item)
def dequeue(self):
assert not self.isEmpty(), "Cannot dequeue from an empty queue."
return self._qList.pop(0)
从以上操作可以看出,length()和isEmpty()的时间复杂度是O(1)。enqueue()和dequeue()的时间复杂度是O(n)。
基于数组的实现
这里的数组可以看成一个环形数组(circular array),另外还需要两个指针,一个指向队头,另一个指向队尾。如下图:
其特点是在插入和删除元素时,其他元素不需要进行移位,只需要移动两个指针便可。
在进行插入元素时,如果数组还有足够的容量,添加新元素,back指针向后移动一位。删除元素时,只需把要删除元素所在位置设置为None,再将front指针后移一位即可。但也有可能碰到以下特殊情况:
在这种情况下,由于我们使用的是环形数组,新元素会被添加到数组索引0的位置,而back指针也会移动至该位置。
数组实现方式的缺陷显然是容量有限。
#-*-coding: utf-8-*-
# 使用数组来实现队列
from myarray import Array
class Queue(object):
def __init__(self, maxSize):
self._count = 0
self._front = 0 # 初始化front指针指向索引0的位置
self._back = maxSize - 1 # 初始化back指针指向索引maxSize - 1的位置
self._qArray = Array(maxSize)
def isEmpty(self):
return self._count == 0
def isFull(self):
return self._count == len(self._qArray)
def __len__(self):
return self._count
def enqueue(self, item):
assert not self.isFull(), "Cannot enqueue to a full queue."
maxSize = len(self._qArray)
self._back = (self._back + 1) % maxSize # 注意此处
self._qArray[self._back] = item
self._count += 1
def dequeue(self):
assert not self.isEmpty(), "Cannot dequeue from an empty queue."
item = self._qArray[self._front]
maxSize = len(self._qArray)
self._front = (self._front + 1) % maxSize
self._count -= 1
return item
基于数组的实现方式,所有方法的时间复杂度都是O(1),因为没有元素移位出现。
基于链表的实现
基于链表的实现方式,是在一个链表上使用头指针和尾指针,头指针指向队头,尾指针指向队尾。
#-*-coding: utf-8-*-
# 使用链表实现队列
class Queue(object):
def __init__(self):
self._qhead = None
self._qtail = None
self._count = 0
def isEmpty(self):
return self._count == 0
def __len__(self):
return self._count
def enqueue(self, item):
node = _QueueNode(item)
if self.isEmpty():
self._qhead = node
else:
self._qtail.next = node
self._qtail = node
self._count += 1
def dequeue(self):
assert not self.isEmpty(), "Cannot dequeue from an empty queue."
node = self._qhead
if self._qhead is self._qtail:
self._qtail = None
self._qhead = self._qhead.next
self._count -= 1
return node.item
class _QueueNode(object):
def __init__(self, item):
self.item = item
self.next = None
在链表实现方式中,所有方法的时间复杂度都是O(1)。