1. 栈和队列
保存临时数据(缓存)
只支持数据项的存储和访问,不支持数据项之间的任何关系
线性表作为栈和队列的实现结构
栈:先进后出(取碗) 队列:先进先出(排队)
2. 栈
存入,访问,删除元素
任何时候可以访问,删除的元素都是最后一个元素
存储方式(2种):顺序栈,链栈
入栈:插入元素
出栈:删除元素
2.1 顺序栈
使用顺序表作为存储结构,利用一组地址连续的存储单元依次自栈底到栈顶的元素,附设top指示栈顶。顺序表的后端插入和删除为 O(1),使用表尾作为栈顶。
| <-- 栈顶(top) |
E |
|
D |
|
C |
|
B |
|
A | <-- 栈底(base) |
1. #顺序栈的实现,利用list存储栈的元素
class StackUnderflow(ValueError):
pass
class SStack():
def __init__(self):
self._elem = [] #所有栈操作都映射到list
def is_empty(self):
return self._elem == []
def top(self):
#查看栈顶元素
if self._elem == []:
raise(StackUnderflow('in SStack.pop()'))
else:
return self._elem[-1]
def push(self,data):
#入栈
self._elem.append(data)
def pop(self):
#出栈
if self._elem == []:
raise(StackUnderflow('in SStack.pop()'))
else:
return self._elem.pop() #调用自带的pop方法
a = SStack()
a.push(1)
a.push(2)
a.top()
a.pop
print(a.pop())
3. 队列
队列:先进先出的线性表
它只允许在表的一端插入,而在另一端删除
出队 <-- | A1 A2 | ….. | An | <--入队 |
| | 队头 |
| | 队尾 |
|
双端队列:限定插入和删除操作在表的两端进行的线性表,实际应用较少
3.1 链队列
链队列:使用链表表示的队列(队列也要2种储方式),需要两个指针(指向队头和队尾指针)才能惟一确定。链队列为空的条件是头指针和尾指针均指向头结点。
#链队列
class Node(object):
def __init__(self,elem,next_=None):
self.elem = elem
self.next = next_
class LQueue(object):
def __init__(self):
self._front = None
self._rear = None
def is_empty(self):
return self._front is None
def peek(self):
#查看队头
if self.is_empty():
print('queue is empty')
return self._front.elem
def dequeue(self):
#出队
if self.is_empty():
print('queue is empty')
e = self._front.elem
self._front = self._front.next
return e
def enqueue(self,e):
#入队
p = Node(e)
if self.is_empty():
self._front = p
self._rear = p
else:
self._rear.next = p
self._rear = p
a = LQueue()
print(a.is_empty())
a.enqueue(1)
a.enqueue(2)
a.enqueue(3)
print(a.peek())
a.dequeue()
print(a.peek())
3.1 队列的顺序表示与实现
队列头指针:front 尾指针:rear
循环队列: 队空:front =rear
队满:(1)设置标志位
(2)头指针在尾指针的下一位:front==(rear+1)%max_size
将在表里留下一个不用的空位
实现:
#思路:基于循环顺序表实现的
#使用固定大小的list实现
#_elem:队列的元素存储区
#_head:队列首元素
#_len:存储区有效容量
#新入队的元素位置:_head+_num
#_num=_len:队列已满,若出现入队操作,扩大内存区
#_num = 0:队列空
class QueueUnderflow(ValueError):
pass
class SQueue():
def __init__(self,init_len=4):
self._len = init_len #存储区长度
self._elem = [0]*init_len #元素存储
self._head = 0 #表头元素下标
self._num = 0 #元素个数
def is_empty(self):
return self._num == 0
def peek(self):
#查看队头元素
if self._num == 0 :
raise QueueUnderflow
return self._elem[self._head]
def dequeue(self):
#出队
if self._num == 0:
raise QueueUnderflow
e = self._elem[self._head] #取出队头并返回
self._head = (self._head+1)%self._len #头指针指向新的队头
self._num -= 1 #队列元素数量减1
return e
def enqueue(self,e):
#入队
if self._num == self._len:
self.__extend()
self._elem[(self._head+self._num)%self._len] = e
self._num += 1
def __extend(self):
#队列满时扩大内存
old_len = self._len
self._len = 2*old_len
new_elem = [0]*self._len
for i in range(old_len):
new_elem[i] = self._elem[(self._head+i)%old_len]
self._elem,self._head = new_elem, 0
sq = SQueue()
sq.enqueue(1)
sq.enqueue(2)
sq.enqueue(3)
sq.enqueue(4)
sq.enqueue(5)
print(sq.peek())
print(sq.dequeue())
print(sq.peek())