栈与队列是程序设计中被广泛应用的两种重要的数据结构,都是在特定范围的存储单元内存储数据,这些数据都可以被重新取出使用,与线性表相比,他们的插入和删除受到更多的约束,固又称限定性的线性表结构。他们是最简单的缓存结构,他们只支持数据项的存储与访问,不支持数据项之间的任何关系。因此,这两种数据集合都很小,很简单,其中最重要的操作就是元素的存入与取出。作为数据结构,他们还需要几个任何数据结构都需要的操作,如结构的创建,检查是否为空状态等。
在计算中,中间数据对象的生成有早有晚,存在时间上的先后顺序。在后面使用这些元素时,也可能需要考虑他们的生成时间顺序。
→栈是保证元素后进先出(后存入者先使用,Last In First Out,LIFO)关系的结构。
→队列是保证元素先进先出(先存入者先使用,First In First Out)关系的结构。
栈是一种容器,可存入数据,访问元素,删除元素等。存入栈中的元素相互之间没有任何具体关系,只有到来的时间先后顺序。在这里没有元素的位置,元素的前后顺序等概念。栈的基本性质保证,在任何时刻可以访问,删除的元素都是在此之前的最后存入的那个元素。因此,栈确定了一种默认元素的访问顺序,访问数无需其他信息。
ADT Stack:
Stack(self) #创建空栈
is_empty(self) #判断栈是否为空,空时返回True否则返回False
push(self,e) #将元素elem加入栈,称为压入或推入
pop(self) #删除栈里最后压入的元素并将其返回,常称为弹出
top(self) #取得栈里最后压入的元素,不弹出
把数组的首元素当做栈底,同时记录栈中的个数size,假设数组的首地址为arr,压栈的操作就是将元素放入arr[size],弹栈就是取数组arr[size-1]的元素,然后执行size减一,根据这个原理实现栈。
#!/usr/bin/python
# -*- coding:utf-8 -*-
#实现栈
#方法一:数组实现栈
class MyStack:
__slots__ = ('items')#该属性仅对当前类有用 继承类没用
#模拟栈
def __init__(self):
self.items = []
#判断栈是否为空
def is_empty(self):
return len(self.items)==0
#返回栈的大小
def size(self):
return len((self.items))
#返回栈顶元素
def top(self):
if not self.is_empty():
return self.items[len(self.items)-1]
else:
return None
#弹栈
def pop(self):
if len(self.items)>0:
return self.items.pop()
else:
print('栈已经为空')
return None
#压栈
def push(self,item):
self.items.append(item)
if __name__ == "__main__":
s = MyStack()
s.push(4)
s.push(3)
s.push(2)
s.push(1)
print('栈顶元素: '+str(s.top()))
print('栈大小为: '+str(s.size()))
s.pop()
print('弹栈成功')
栈顶元素: 1
栈大小为: 4
弹栈成功
[Finished in 0.1s]
由于数组的初始大小会占用多余的内存,且在元素量未知的情况下可能会出现扩容的情况,因此也可以使用链表实现栈,但相应的增加了空间代价记录指针位置,但也是一种方法。在执行压栈操作时,只需把链表首节点的next指针指向当前压入元素,再把当前元素next指针指向之前首节点指向的元素地址即可,弹出元素就更简单了,只需修改首节点指针到head.next.next的位置,显示head.next.data即可完成弹栈操作。
#方法二:链表实现
class LNode:
def __init__(self,x,next_=None):
self.data = x
self.next = next_
class MyStack:
def __init__(self):
#pHead=LNode()
self.data = None
self.next = None
#判断stack是否为空,如果空返回true,否则返回false
def empty(self):
if self.next ==None:
return True
else:
return False
#获取栈中元素个数
def size(self):
size = 0
p = self.next
while p != None:
p = p.next
size += 1
return size
#入栈:放入栈顶
def push(self,e):
p = LNode(e)
p.next = self.next#None
self.next = p
def pop(self):
tmp = self.next
if tmp != None:
self.next = tmp.next
return tmp.data
print('栈已空')
return None
def top(self):
if self.next != None:
return self.next.data
print('栈已空')
return None
if __name__ == '__main__':
stack = MyStack()
stack.push(4)
stack.push(3)
stack.push(2)
stack.push(1)
print('栈顶元素为: '+str(stack.top()))
print('栈大小为: '+str(stack.size()))
stack.pop()
print('弹栈成功')
与前面数组不同的是,这里需要自定义链表结构LNode.
栈顶元素为: 1
栈大小为: 4
弹栈成功
[Finished in 0.1s]
队列也称为队,队列中也没有位置的概念,只支持默认的元素存入与取出,其特点就是保证在任何时候访问或删除的元素,都是在此前最早存入队列且尚未删除的那个元素。可以借用数据的存储顺序表示数据的存储时间的先后关系,用线性表作为队列的实现结构,利用元素的存储顺序表示其访问顺序。
ADT Queue:
Queue(self) #创建空队列
is_empty(self) #判断队列是否为空,空返回True否则返回False
enqueue(self,e) #将元素elem加入队列,称为入队
dequeue(self) #删除队里最早进入的元素,称为出队
peek(self) #查看队列最早进入的元素,不删除
用两个指针front和rear记录队列的首尾元素位置,入队只需将入队元素放到rear的位置,同时执行rear+,出队时只需执行front+的操作即可。
#!/usr/bin/python
# -*- coding:utf-8 -*-
#方法一:队列实现
class MyQueue:
def __init__(self):
self.arr = []
self.front = 0#队列头
self.rear = 0#队列尾
def isEmpty(self):
return self.front == self.rear
#返回队列的大小
def size(self):
return self.rear - self.front
#返回队列首元素
def getFront(self):
if self.isEmpty():
return None
return self.arr[self.front]
#返回队尾元素
def getBack(self):
if self.isEmpty():
return None
return self.arr[self.rear-1]
#删除队列头元素
def deQueue(self):
if self.rear>self.front:
self.front +=1
else:
print("队列已空")
#增加队列元素
def enQueue(self,item):
self.arr.append(item)
self.rear += 1
if __name__ == '__main__':
queue = MyQueue()
queue.enQueue(1)
queue.enQueue(2)
print('队列首元素'+str(queue.getFront()))
print('队尾元素'+str(queue.getBack()))
print('队列大小:'+str(queue.size()))
队列首元素1
队尾元素2
队列大小:2
[Finished in 0.1s]
采用链表实现队列与实现栈方法类似,通过使用头指针pHead与尾指针pEnd指向对首先与队尾元素,新元素入队只需将pEnd指针指向新元素并修改pEnd+1,出队则需要修改pHead指针到pHead.next.next,其他不变。
#方法二:链表实现
class LNode:
def __init__(self,x,next_=None):
self.data = x
self.next = next_
class MyQueue:
#分配头结点
def __init__(self):
self.pHead = None
self.pEnd = None
#判断队列是否为空
def isEmpty(self):
if self.pHead == None:
return True
else:
return False
#获取栈中元素
def size(self):
size = 0
p = self.pHead
while p != None:
p = p.next
size += 1
return size
#入队列:向队列加入元素e
def enQueue(self,e):
p = LNode(e)
p.next = None
if self.pHead == None:
self.pHead = self.pEnd = p
else:
self.pEnd.next = p
self.pEnd = p
#出队列
def deQueue(self):
if self.pHead == None:
print("出队列失败,队列为空")
print('出队元素:'+str(self.pHead.data))
self.pHead = self.pHead.next
if self.pHead == None:
self.pEnd = None
#取得队列首元素
def getFront(self):
if self.pHead == None:
print("队列为空")
return None
return self.pHead.data
#取得队尾元素
def getBack(self):
if self.pEnd == None:
print("队列为空")
return None
return self.pEnd.data
if __name__ == "__main__":
queue = MyQueue()
queue.enQueue(1)
queue.enQueue(2)
print('队列首元素'+str(queue.getFront()))
print('队尾元素'+str(queue.getBack()))
print('队列大小:'+str(queue.size()))
队列首元素1
队尾元素2
队列大小:2
[Finished in 0.1s]