循环队列
队列
先进先出(FIFO)结构
不管是栈
还是队列
, 必须尽可能以效率最大化的方式实现, 如: 添加元素在列表末尾
队列要实现的需求
- 创建空队列
- is_empty 判断是否为空
- enqueue 入队
- dequeue 出对
- peek 查看队列里最早进入的元素但是不删除
由于队列先进先出的特殊性, 在使用list实现的时候, 总会有一个操作出现O(n)的时间损耗, 所以采用循环队列
的方式, 即先初始化一个固定大小的空间, 若插入元素发现空间不够时自动扩大空间
- 普通队列:
如果采用python的list结构来简单实现一段添加,一段弹出, 必定会出现添加或删除的时间复杂度是O(n)
- 循环队列
能保证空间得到有效利用, 同时保证插入
和弹出
的时间复杂度都是O(1)
下例采用循环队列的方式实现
#!/usr/bin/env python
# coding:utf-8
class Queue:
def __init__(self, init_len=8): # 默认存储区有8个位置存储
self._len = init_len # 存储区长度
self._elems = [0]*init_len # 存放队列元素
self._head = 0 # 表头元素下标, 弹出元素时以该下表为准
self._num = 0 # 队列中实际元素个数
def enqueue(self, e):
"""入队"""
if self._num == self._len:
self.__extend()
self._elems[(self._head+self._num)%self._len] = e
self._num += 1
def dequeue(self):
"""出队"""
if self._num == 0:
print '队列为空'
return
e = self._elems[self._head]
self._head = (self._head+1)%self._len
self._num -= 1
return e
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
def is_empty(self):
return self._num == 0
def peek(self):
"""取出队首元素但不删除"""
if self._num == 0:
print '队列为空'
return
return self._elems[self._head]
if __name__ == '__main__':
q = Queue()
for i in range(10):
q.enqueue(i)
for i in range(10):
print q.dequeue()
print q.is_empty()
- 入队:
用num来做要插入元素的下标, 每进入一个元素num+1, 直到队列满, 拓展空间 - 出队:
用head来做要弹出元素的下标, 每弹出一个, num-1, head=(head+1)%len - 拓展空间:
这里拓展倍数是2, 然后把原来队里中的内容复制到新的队列中, 但是要保证在新队列中原来元素的位置不能更改