在董建明《数据结构与算法》一课中,学到两种数据结构,结合自己所查的资料与本人的一点点理解,在此做出整理,结合《数据结构(python)》一书给出栈与队列的实现方式,并结合两者实现停车场管理问题。
特点:先进后出,类似码书,先放反而后出。由栈顶与栈底构成
笔者理解两者的差异主要在他们在计算机存储方式的不同,链栈用的是分散的存储空间,而顺序栈则使用连续的存储空间。
笔者将栈一python列表的形式为基础;
实现以下几个功能:
(1)进栈
(2)出栈
(3)输出栈的长度
(4)判断栈是否为满或空
(5)输出栈中所有元素
class SqStack():
def __init__(self,max):
self.maxSize=max
self.stackElem=[None]*self.maxSize
#以列表的实现顺序栈
self.top=0
def clear(self):
self.top=0
def isEmpty(self):
return self.top==0
def length(self):
return self.top
# def peek(self):#返回栈顶元素
# if not self.isEmpty():
# return self.stackElem[self.top-1]
# self.top-=1
# else:
# return None
def push(self,x):#数据元素X入栈
if self.top==self.maxSize:
raise Exception("栈满了")
self.stackElem[self.top]=x
self.top+=1
def pop(self):#出栈
if self.top==0:
raise Exception("栈是空的")
self.top -= 1
return self.stackElem[self.top]
def display(self):#遍历栈
for i in range(self.top-1,-1,-1):
print(self.stackElem[i],end=' ')
print()
其特点是先进先出,就像我们现实生活的排队,先进先出。关键部分是队首(front)与队尾(rear)
链队列笔者的理解是不定存储空间的列表基础下的数据结构,循环队列则是定存储空间的列表基础下的数据结构。
那么在实现循环队列上,有一定的技巧,这里笔者按照《数据结构(python)》中取余的方式来解决队列的“假满问题”;front=rear时队空;front=(rear+1)%size时对满。
同样以list为基础进行实现下面几个功能
(1)出队
(2)入队
(3)返回队长
(4)判断队满队空
(5)输出队列所有元素
class Queue():
def __init__(self):
self.Maxsize=7
self.qE=[None]*self.Maxsize
self.front=0#队首
self.rear=0#队尾
# 定义一个长度为6的循环队列
def isEmpty(self):
return self.front==self.rear
#判断是否为空队列
def lenth(self):
return (self.rear-self.front+7)%7
#返回队列长度
def offer(self,x):
if(self.rear+1)%self.Maxsize==self.front:
raise Exception("队列满了")
self.qE[self.rear]=x
self.rear=(self.rear+1)%self.Maxsize
#x入队
def poll(self):
if self.isEmpty():
raise Exception("队列是空的")
p=self.qE[self.front]
self.front=(self.front+1)%self.Maxsize
#print('队首元素%d出列'%(p))
return p
#队首出队
def disploy(self):
for i in range(self.front,self.rear):
print(self.qE[i],end=' ')
#将队列元素全部输出
设停车场内只有一个可停放n辆汽车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停放在车场的最北端),若车场内已停满n辆汽车,则后来的汽车只能在门外的便道上等候,一旦有车开走,则排在便道上的第一辆车即可开入;当停车场内某辆车要离开时,在它之后开入的车辆必须先退出车场为它让路,待该辆车开出大门外,其它车辆再按原次序进入车场,每辆停放在车场的车在它离开停车场时必须按它停留的时间长短交纳费用。试为停车场编制按上述要求进行管理的模拟程序。
综合利用栈和队列模拟停车场管理,学习利用栈和队列解决实际问题。
以栈模拟停车场,以队列模拟车场外的便道,按照从终端读入的输入数据序列进行模拟管理。每一组输入数据包括三个数据项:汽车“到达”或“离去”信息、汽车牌照号码及到达或离去的时刻,对每一组输入数据进行操作后的输出数据为:若是车辆到达,则输出汽车在停车场内或便道上的停车位置;若是车离去;则输出汽车在停车场内停留的时间和应交纳的费用(在便道上停留的时间不收费)。栈以顺序结构实现,队列以链表实现。
需另设一个栈,临时停放为给要离去的汽车让路而从停车场退出来的汽车,也用顺序存储结构实现。输入数据按到达或离去的时刻有序。栈中每个元素表示一辆汽车,包含两个数据项:汽车的牌照号码和进入停车场的时刻。
设n=2,输入数据为:(‘A’,1,5),(‘A’,2,10),(‘D’,1,15),(‘A’,3, 20), (‘A’,4,25),(‘A’,5,30),(‘D’,2,35),(‘D’,4,40),(‘E’,0,0)。每一组输入数据包括三个数据项:汽车“到达”或“离去”信息、汽车牌照号码及到达或离去的时刻,其中,‘A’表示到达;‘D’表示离去,‘E’表示输入结束。(如第一个表示车1时间5开入)
(1) 定义好顺序栈类作为停车场(carStack),栈的最大停车空间为2。
(2) 定义一个循环队列类作为停车通道(Carqueue),(容量为6)
(3) 定义一个Car类,Car有变量number(车号)、gettime(车停进的时间)leavetime(车离开停车场的时间)、cost(车停进车场的费用),设定4个变量的初始均为None;定义类方法parkover()输出车最后的出栈时间与停车费用或其仍在栈中停车
(4) 设置一个列表carlist,储存输入的Car类;设置输入形式为如A,1,2的实行,以“,”隔开化成一个输入列表,规则同题目要求一致
(5) 如果停车场(栈)满,则等车停车结束(出栈)并调用parkover()方法输出车子的进出站时间、需要交纳的停车费用(以5元/h计费),再停进下一辆车(队列出队;顺序栈进栈),这时的时间作为入栈车的新的停进时间(gettime=leavetime)
(6) 如果此事栈中仍有车停在其中,输出其进栈时的时间。
from Order_Stack import SqStack
from Circular_queue import Queue
class Car:
def __init__(self):
self.number=None
self.gettime=None
self.leavetime=None
self.cost=None
def parkover(self):
if self.leavetime == None:
print('车库中车子%d停车未结束,您的到达时间为:%d' % (self.number, self.gettime))
else:
self.cost = (self.leavetime - self.gettime) * 5
print('车子%d停车结束,您的到达时间为:%d,离开时间为:%d,您的停车费用为:%d元' % (self.number, self.gettime, self.leavetime, self.cost))
q = 1
carlist = []
while q == 1:
x = list(input('请输入车的相关信息:').split(','))
# if x[0] == 'D':#程序结束
if x[0] == 'E':#程序结束
break
elif x[0] == 'A': # 车子到达停车
car = Car()
car.number = int(x[1])
car.gettime = int(x[2])
carlist.append(car)
# elif x[0] == 'B': # 车子开出
elif x[0] == 'D': # 车子开出
for i in range(len(carlist)):
if carlist[i].number == int(x[1]):
carlist[i].leavetime = int(x[2])
# 设计输入部分程序
letime=[]
for i in range(len(carlist)):
if carlist[i].leavetime!=None:
letime.append(carlist[i].leavetime)
for i in range(0,len(letime)):
for j in range(i+2,len(carlist)):
if carlist[j].gettime<letime[i]:
carlist[j].gettime = letime[i]
#求出所有车的真正的进场停车的时间点
Carqueue=Queue()
for i in range(len(carlist)):
Carqueue.offer(carlist[i])
Carstack=SqStack(2)
j=0
while j<Carqueue.lenth():
if Carstack.length()<2:
Carstack.push(carlist[j])
j+=1
# 只有两个停车位,有位置直接停进
else:
if Carstack.stackElem[0].leavetime==None:
l = Carstack.pop()
l.parkover()
print('车子%d停进'%(j+1))
# 车位已满,旧车出,新来车停进
elif Carstack.stackElem[0].leavetime!=None:
k=Carstack.pop()
l=Carstack.pop()
print('车子%d出栈让路,车子%d退出停车场'%(k.number,l.number))
l.parkover()
Carstack.push(k)
print('车子%d停进' % (j+1))
for i in range(Carstack.length()):
Carstack.stackElem[i].parkover()
#输出栈中剩余车辆的信息
笔者停车管理问题实现形式是无脑循环,与if判断,没有什么复杂的算法实现;同时没有考虑前车比后车晚走、前车与后车同时走等的情况(吐糟菜鸡笔者)。欢迎大佬下方留言,给出更好的解决方案。