队列ADT(抽象数据类型)如下所示:
Q.enqueue(e)
Add element e to the back of queue Q.
Q.dequeue()
Remove and return the first element from queue Q;
an error occurs if the queue is empty.
Q.first()
Return a reference to the element at the front of queue Q,
without removing it; an error occurs if the queue is empty.
Q.is_empty()
Return True if queue Q does not contain any elements.
len(Q)
Return the number of elements in queue Q;
in Python, we implement this with the special method
__len__
使用一个Python列表来实现上面的队列ADT(抽象数据类型),也使用一个循环数组来实现相同的队列ADT
下面是array_stack.py
"""Basic example of an adapter class to provide a stack interface to Python's list."""
#from ..exceptions import Empty
class Empty(Exception):
pass
class ArrayStack:
"""LIFO Stack implementation using a Python list as underlying storage."""
def __init__(self):
"""Create an empty stack."""
self._data = [] # nonpublic list instance
def __len__(self):
"""Return the number of elements in the stack."""
return len(self._data)
def is_empty(self):
"""Return True if the stack is empty."""
return len(self._data) == 0
def push(self, e):
"""Add element e to the top of the stack."""
self._data.append(e) # new item stored at end of list
def top(self):
"""Return (but do not remove) the element at the top of the stack.
Raise Empty exception if the stack is empty.
"""
if self.is_empty():
raise Empty('Stack is empty')
return self._data[-1] # the last item in the list
def pop(self):
"""Remove and return the element from the top of the stack (i.e., LIFO).
Raise Empty exception if the stack is empty.
"""
if self.is_empty():
raise Empty('Stack is empty')
return self._data.pop() # remove last item from list
if __name__ == '__main__':
S = ArrayStack() # contents: [ ]
S.push(5) # contents: [5]
S.push(3) # contents: [5, 3]
print(len(S)) # contents: [5, 3]; outputs 2
print(S.pop()) # contents: [5]; outputs 3
print(S.is_empty()) # contents: [5]; outputs False
print(S.pop()) # contents: [ ]; outputs 5
print(S.is_empty()) # contents: [ ]; outputs True
S.push(7) # contents: [7]
S.push(9) # contents: [7, 9]
print(S.top()) # contents: [7, 9]; outputs 9
S.push(4) # contents: [7, 9, 4]
print(len(S)) # contents: [7, 9, 4]; outputs 3
print(S.pop()) # contents: [7, 9]; outputs 4
S.push(6) # contents: [7, 9, 6]
S.push(8) # contents: [7, 9, 6, 8]
print(S.pop()) # contents: [7, 9, 6]; outputs 8
1.修改ArrayStack实现(array_stack.py),使堆栈的容量仅限于maxlen元素,其中maxlen是构造函数的可选参数(默认为无)。如果在堆栈处于满容量时调用push,则抛出完全异常(定义类似于空)。
from array_stack import ArrayStack
import unittest
class Full(Exception):
pass
class MyStack(ArrayStack):
def __init__(self, maxlen=None):
super().__init__()
self._maxlen = maxlen
def push(self, e):
"""Add element e to the top of the stack."""
if self._maxlen != None:
if self.__len__() >= self._maxlen:
raise Full("Stack is full!!!")
self._data.append(e)
if __name__ == '__main__':
S = MyStack(5)
for i in range(5):
try:
S.push(i)
except Exception as e:
print(e)
S.push(2)
2.在前面的练习中,我们假设底层列表最初是空的。重做这个练习,这次预先分配一个长度等于堆栈最大容量的底层列表。
from array_stack import ArrayStack
class Full(Exception):
pass
class MyStack1(ArrayStack):
def __init__(self, maxlen=None):
self._maxlen = maxlen
self._data = [] if maxlen is None else [None] * maxlen
def push(self, e):
"""Add element e to the top of the stack."""
if self._maxlen != None:
if self.__len__() >= self._maxlen:
raise Full("Stack is full!!!")
self._data.append(e)
if __name__ == '__main__':
S = MyStack1(5)
S.pop()
S.push(2)
3.给出讲座中提到的双端队列ADT的一个完整的ArrayDeque实现。如下图:
class Empty(Exception):
pass
class ArrayQueue:
"""FIFO queue implementation using a Python list as underlying storage."""
DEFAULT_CAPACITY = 10 # moderate capacity for all new queues
def __init__(self):
"""Create an empty queue."""
self._data = [None] * ArrayQueue.DEFAULT_CAPACITY # Note we use a list to implement Array
self._size = 0
self._front = 0
def __len__(self):
"""Return the number of elements in the queue."""
return self._size
def is_empty(self):
"""Return True if the queue is empty."""
return self._size == 0
def first(self):
"""Return (but do not remove) the element at the front of the queue.
Raise Empty exception if the queue is empty.
"""
if self.is_empty():
raise Empty('Queue is empty')
return self._data[self._front]
def dequeue(self):
"""Remove and return the first element of the queue (i.e., FIFO).
Raise Empty exception if the queue is empty.
"""
if self.is_empty():
raise Empty('Queue is empty')
answer = self._data[self._front]
self._data[self._front] = None # help garbage collection
self._front = (self._front + 1) % len(self._data) # Circular Array ---Wei Pang
self._size -= 1
return answer
def enqueue(self, e):
"""Add an element to the back of queue."""
if self._size == len(self._data):
self._resize(2 * len(self.data)) # double the array size
avail = (self._front + self._size) % len(self._data) # Circular Array again ---Wei Pang
self._data[avail] = e
self._size += 1
def _resize(self, cap): # we assume cap >= len(self)
"""Resize to a new list of capacity >= len(self)."""
old = self._data # keep track of existing list
self._data = [None] * cap # allocate list with new capacity
walk = self._front
for k in range(self._size): # only consider existing elements
self._data[k] = old[walk] # intentionally shift indices
walk = (1 + walk) % len(old) # use old size as modulus
self._front = 0 # front has been realigned
if __name__ == '__main__':
Q= ArrayQueue()
# return value first<-- Q <--Last
Q.enqueue(5) # – [5]
Q.enqueue(3) # – [5, 3]
a=len(Q) # 2 [5, 3]
a=Q.dequeue( ) # 5 [3]
a=Q.is_empty( ) # False [3]
a=Q.dequeue( ) # 3 [ ]
a=Q.is_empty( ) # True [ ]
# Q.dequeue( ) # “error” [ ]
a=Q.enqueue(7) # – [7]
a=Q.enqueue(9) # – [7, 9]
a=Q.first() # 7 [7, 9]
a=Q.enqueue(4) # – [7, 9, 4]
a = Q.__len__() # 3 [7, 9, 4]
a=Q.dequeue( ) # 7 [9, 4]