上节内容回顾:python数据结构与算法——(一)数组列表和链表
本节中介绍队列(queue)和栈(stack)。队列和栈很类似,不同的是,队列是先进先出结构(FIFO, first in first out),如日常生活中的排队;而栈是后进先出结构(LIFO, last in first out),如在桌子上放一沓书,先放的一本在最下面,最后放的一本在最上面,而拿的时候是先拿最上面的一本。
1. 队列
队列需要从头删除元素,从尾部增加元素。下面有几种方式实现队列。
1.1 用list实现
class ListQueue(object):
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self,item):
self.items.append(item)
def pop(self):
return self.items.pop(0)
def size(self):
return len(self.items)
详细代码见github:list_queue.py
用list,直接调用list的方法可以很容易实现队列,但list.pop(0)会导致所有list元素前移,时间复杂度为O(n)。append的时间复杂度为O(1),但如果内存不够还需要重新分配内存。所以用这个方式的效率是非常低的。
1.2 用链表实现
在上一节中,我们实现了单链表LinkedList。LinkedList有popleft和append这两个方法,且都是O(1)。因此可以高效实现队列。
class FullError(object):
pass
class EmptyError(object):
pass
class Queue(object):
def __init__(self, maxsize=None):
self.maxsize = maxsize
self._item_link_list = LinkedList(self.maxsize)
def __len__(self):
return len(self._item_link_list)
def push(self,value):
"""队尾添加元素"""
if self.maxsize is not None and len(self) >= self.maxsize:
raise FullError('queue full')
return self._item_link_list.append(value)
def pop(self):
""" 队列头部删除元素"""
if len(self) <= 0:
raise EmptyError('empty queue')
return self._item_link_list.popleft()
详细代码见github:queue.py
1.3 用数组实现
因为数组是预先分配固定内存,如果知道队列的最大长度,也可用数组实现。
用两个指针head和tail,当我们向数组中增加元素push时,head指针前移;当我们删除元素pop时,tail指针前移。队列的长度是head-tail,且此长度不能超过初始化长度。如果head指针已经到数组未尾后,则又回到头部重新开始,如0,1,2,3,4,0,1,2,3,4,…,如此循环下去。
下面我们用上一节的Array ADT实现。
class FullError(object):
pass
class ArrayQueue(object):
def __init__(self, maxsize):
self.maxsize = maxsize
self.array = Array(self.maxsize)
self.head = 0
self.tail = 0
def __len__(self):
return self.head - self.tail
def push(self,value):
if len(self) >= self.maxsize:
raise FullError('queue full')
self.array[self.head % self.maxsize] = value
self.head += 1
def pop(self):
value = self.array[self.tail % self.maxsize]
self.tail += 1
return value
详细代码见github:array_queue.py
2. 双端队列
双端队列,在队头和队尾都能进出,即拥有append、appendleft、pop、popleft这几个方法。在python内置中也有双端队列,collection.deque模块。
2.1 双链表实现双端队列
在上一节中,我们实现了双链表CircularDoubleLinkedList ADT,下面用它实现双端队列。
class Deque(CircularDoubleLinkedList):
def pop(self):
"""删除尾部节点"""
if len(self) == 0:
raise Exception('empty')
tailnode = self.tailnode()
value = tailnode.value
self.remove(tailnode)
return value
def popleft(self):
"""删除头部节点"""
if len(self) == 0:
raise Exception('empty')
headnode = self.headnode()
value = headnode.value
self.remove(headnode)
return value
详细代码见github:deque.py
2.2 python内置deque实现队列
from collections import deque
class PythonDequeQueue(object):
def __init__(self, maxsize=None):
self.maxsize = maxsize
self._item_python_deque = deque(maxlen=self.maxsize)
def __len__(self):
return len(self._item_python_deque)
def push(self):
"""队尾添加元素"""
if self.maxsize is not None and len(self) >= self.maxsize:
raise FullError('queue full')
return self._item_python_deque.append(value)
def pop(self):
"""队列头部删除元素"""
if len(self) <= 0:
raise EmptyError('empty queue')
return self._item_python_deque.popleft()
详细代码见github:python_deque_queue.py
3. 栈
栈(stack),先进后出结构,即在尾部增删元素,下面有几种方式实现。
3.1 deque实现栈
用刚刚实现的双端队列实现栈。
class Stack(object):
def __init__(self):
self.deque = Deque()
def push(self,value):
return self.deque.append(value)
def pop(self):
return self.deque.pop()
def __len__(self):
return len(self.deque)
def is_empty(self):
return len(self) == 0
也可用python内置的deque实现,将stack的__init__方法中,deque替换为python的deque模块。
from collections import deque
self.deque = deque()
详细代码见github:stack.py
3.2 数组实现栈
因为stack是先进后出结构,只用一个指针即可实现。
class ArrayStack(object):
def __init__(self,maxsize):
self.maxsize = maxsize
self.array = Array(self.maxsize)
self.tail = 0
def __len__(self):
return self.tail
def push(self,value):
if len(self) >= self.maxsize:
raise FullError('stack full')
self.array[self.tail] = value
self.tail += 1
def pop(self):
if len(self) == 0:
raise Exception('stack empty')
value = self.array[self.tail - 1]
self.tail -= 1
return value
def is_empty(self):
return len(self) == 0
详细代码见github:array_stack.py
4. reference
本文同步发布在我的github.io