一、问题描述
【问题描述】
设停车场是一个可停放n辆汽车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停放在车场的最北端),若车场内己停满n辆汽车,则后来的汽车只能在门外的便道上等候,一旦有车开走,则排在便道上的第一辆车即可开人:当停车场内某辆车要离开时,在它之后进入的车辆必须先退出车场为它让路,待该辆车开出大门外,其他车辆再按原次序进入车场,每辆停放在车场的车在它离开停车场时必须按它停留的时间长短交纳费用。试为停车场编制按上述要求进行管理的模拟程序。
【基本要求】
以栈模拟停车场,以队列模拟车场外的便道,按照从终端读入的输入数据序列进行模拟管理。每一组输入数据包括三个数据项:汽车“到达”或“离去”信息、汽车牌照号码以及到达或离去的时刻。对每一组输入数据进行操作后的输出信息为:若是车辆到达,则输出汽车在停车场内或便道上的停车位置;若是车辆离去,则输出汽车在停车场内停留的时间和应交纳的费用(在便道上停留的时间不收费)。栈以顺序结构实现,队列以链表结构实现。
二、需求分析
1.输入的形式和输入值的范围
(1)停车场容量n,n为正整数。
(2)停车收费标准Price,按时计费。
(3)汽车的状态state,“进入I”或“退出O”。
(4)汽车牌照号码VehicleID,输入一个正整数。
(5)进站或出站的时刻arrivetTime,输入一个正整数,24小时制,到达时间向下取整,离开时间向上取整。
2.输出的形式
演示程序以用户与计算机交互方式执行,即在计算机终端上显示“提示信息”之后,由用户在键盘上输入演示程序中规定的运算命令;相应的输入数据和结果显示在其后。
(1)当输入进站信息后,输出汽车的停车场/便道位置。
(2)当输入出站信息后,输出汽车停车时间以及停车费用。
3.程序所能达到的功能
(1)录入进站车辆的信息。当停车场内车辆数量<停车场容量n时,汽车进站,否则在门外便道上依次等待。
(2)删除出站车辆的信息。当汽车出站时,在其之后进入的车辆必须先退出停车场为其让路,待该车辆开出大门外,其他车辆再按原次序进入停车场,在停车场内的位置-1;此时停在门外便道处的第一辆车可进入停车场停车,在停车场内的位置为n;其它停在便道上的车辆位置-1。
(3)对车辆进行收费。汽车从停车场离开时必须按其停留时间长短交纳费用,在便道上停留的时间不计费。
(4)停车场和便道信息显示。可查看停车场和便道车辆信息,停车场容量,车位余量以及收费标准。
4.测试数据
(1)正确的输入及输出结果
停车场容量为:2
停车费用(元/时):5
停车场管理系统功能界面
1.汽车进入/退出停车场
2.显示停车场基本信息
3.查询停车场内车辆信息
4.查询便道车辆信息
请选择功能:1
汽车的状态(进入/退出----I/O) 车牌号 汽车进出时刻(24小时制,到达时间向下取整,离开时间向上取整)
I 1 10 汽车:1 在停车场的位置为:1。
I 2 11 汽车:2 在停车场的位置为:2。
I 3 12 停车场已满,汽车:3 在便道的位置为:1。
O 1 13 汽车:1 停车时长:3小时,请缴费:15元(收费标准:5元/时)。
E 0 0 结束输入
请选择功能:2
显示停车场的容量,停车价格,车位余量
请选择功能:3
显示停车场内车辆信息包括车牌号和到达时间
请选择功能:4
显示便道车辆信息
请选择功能:
...
(2)错误的输入及输出结果
停车场容量为:-2 ERROR:请输入正整数。
停车费用(元/时):-5 ERROR:请输入正整数。
停车场管理系统功能界面
1.汽车进入/退出停车场
2.显示停车场基本信息
3.查询停车场内车辆信息
4.查询便道车辆信息
请选择功能:5 ERROR!请输入1-4之间的数字。
汽车的状态(进入/退出----I/O) 车牌号 汽车进出时刻(24小时制,到达时间向下取整,离开时间向上取整)
O 1 12 ERROR:未查询到该车辆。
I 3 25 ERROR: 时间格式错误,请输入0-24之间的整数。
I 3 2.5 ERROR: 时间格式错误,请输入0-24之间的整数。
I 4 13 汽车:4 在停车场的位置为:1。
I 4 14 ERROR:该车已在场内,汽车:4 在停车场的位置为:1。
A 1 2 ERROR: 状态错误,请输入I进站/O出站/E退出。
三、概要设计
1.为实现上述程序功能,应以顺序栈表示停车场,以链队列表示便道。抽象数据类型分别如下:
(1)停车场-栈的抽象数据类型定义为:
ADT Stack
{
数据对象:D={ai|ai∈ElemSet,i=1,2,…,n,n≥0}
数据关系:R={<ai-1,ai>|ai-1,ai∈D,i=2,…,n}
约定an端为栈顶,ai为栈底。
基本操作:
InitStack(&S)
操作结果:构造一个空栈。
StackEmpty(S)
初始条件:栈S已存在。
操作结果:若栈S为空栈,则返回true,否则返回false。
StackFull(S)
初始条件:栈S已存在。
操作结果:若栈S为满栈,则返回true,否则返回false。
Push(&S,e)
初始条件:栈S已存在。
操作结果:插入元素e为新的栈顶元素。
Pop(&S,&e)
初始条件:栈S已存在且非空。
操作结果:删除栈S的栈顶元素,并用e返回其值。
}ADT Stack
(2)便道-队列的抽象数据类型定义为:
ADT Queue
{
数据对象:D={ai|ai∈ElemSet,i=1,2,…,n,n≥0}
数据关系:R={<ai-1,ai>|ai-1,ai∈D,i=2,…,n}
约定其中a1端为队头,an端为队尾。
基本操作:
InitQueue(&Q)
操作结果:构造一个空队列Q。
QueueEmpty(Q)
初始条件:队列Q已存在。
操作结果:若Q为空队列,则返回true,否则返回false。
EnQueue(&Q,e)
初始条件:队列Q已存在。
操作结果:插入元素e为Q的新的队尾元素。
DeQueue(&Q,&e)
初始条件:队列Q为非空队列。
操作结果:删除队列Q的队头元素,并用e返回其值。
}ADT Queue
2.本程序模块
(1)主程序模块
void main(){
顺序栈(停车场)的初始化;
链队列(便道)的初始化;
do{
汽车进入/退出停车场;
显示停车场基本信息;
查询停车场内车辆信息;
查询便道车辆信息;
}while(!退出)
}
(2)汽车进/出停车场模块,实现对顺序栈和链队列的操作以及计时计费;
(3)显示停车场基本信息模块;
(4)查询停车场内车辆信息模块,实现对顺序栈的操作;
(5)查询便道车辆信息模块,实现对链队列的操作;
图 1 功能模块图
四、详细设计
1.数据类型定义的伪码描述
(1)停车场
typedef struct{
int VehicleID[10];//车牌号
int arriveTime[10];//汽车到达时间
int top;//栈顶指针
int size;//停车场容量
}SqStack;//顺序栈
(2)便道
typedef struct QNode{
int VehicleID;//车牌号
int arriveTime;//汽车到达时间
Struct QNode *next;//指针域
}QNode,*QueuePtr;//结点名称,结点类型
typedef struct{
QueuePtr front;//队头指针
QueuePtr rear;//队尾指针
}LinkQueue;//链队列
2.主函数和其他函数的伪码算法
int main(){
Initialization();//初始化功能界面
InitStack();//初始化停车场
InitQueue();//初始化便道
while(!退出){
ReadCommand(cmd);//读入一个操作命令符
Interpret(cmd);//解释执行操作命令符
}
return 0;
}//main函数
void Initialization(){
//显示功能菜单:
//汽车进入/退出停车场-------------1
//显示停车场基本信息--------------2
//查询停车场内车辆信息------------3
//查询便道车辆信息----------------4
}
void ReadCommand(char cmd){//读入操作命令符,显示键入操作命令符的提示信息;
do(cmd == getch())
While(cmd[‘1’,‘2’,‘3’,‘4’]);
}
void Interpret(){//解释执行操作命令cmd
switch(cmd){
case ‘1’:IOVehicle();//汽车进出停车场
case ‘2’:ParkInfo();//显示停车场基本信息
case ‘3’:ParkVeInfo();//查询停车场内车辆信息
case ‘4’:PaveVeInfo();//查询便道车辆信息
}//switch
}//Interpret
void IOVehicle(SqStack &S,SqStack &s,LinkQueue &Q,double Price){//汽车进出停车场
cin>>state>>Vehicle>>Time//输入汽车状态(I/O)、车牌号、时间
if(state == ‘I’){//如果汽车进站
if(!StackFull){//栈未满即停车场未满
Push(S,VehicleID,arriveTime);//入栈即汽车进入停车场,开始计时
cout<<S.VehicleID<<S.top+1<<endl;//输出汽车在停车场内的位置
}
else{//栈满即停车场已满
EnQueue(Q,VehicleID);//入队即汽车在便道处排队等待,不计时
cout<<S.VehicleID<<position<<endl;//输出汽车在便道的位置
}
}
else if(state == ‘O’){//如果汽车出站
if(possess){//如果有该汽车信息
if(isTop){//如果该车在栈顶即其后无车
pop(S,VehicleID,arriveTime);//直接出栈
FeeCalculate(arriveTime,leaveTime,Price)//计时计费
}
}
else{//该车后面有其他车辆
for(i=S.top; i>=0; i--) {//栈顶到栈底循环
if(S.VehicleID[i]!=VehicleID) {//如果信息不匹配
Pop(S,VehicleID,leaveTime);//出栈为其让路
Push(s,VehicleID,arriveTime);//进入临时车道
}
else{//如果信息匹配
Pop(S,VehicleID,arriveTime);//出栈
FeeCalculate(arriveTime[],leaveTime[],Price)//计时计费
}
while(!StackEmpty(s)){//临时车道非空时
Pop(s,VehicleID,arriveTime);//退出临时车道
Push(S,VehicleID,arriveTime);//依次回到停车场
}
if(!QueueEmpty(Q)){//如果便道上有车,则则可进入停车场
DeQueue(Q,VehicleID);//出便道
Push(S,VehicleID,arriveTime);//进入停车场
}else cout<<VehicleID<<”信息不存在”<<endl;
}
}
void ParkInfo(int n,double Price){//显示停车场基本信息
cout<<”容量:”<<n<<”价格:”<<Price<<”车位余量:”<<n-S.top-1<<endl;
}
void ParkVeInfo(SqStack S){//查询停车场内车辆信息
if(S.top == -1) {
cout<<”停车场内无车辆”<<endl;
Flag = 0;
}
While(S.top != -1 && Flag){//停车场非空
Cout<<S.VehicleID<<S.arriveTime<<endl;//输出
S.top--;//栈顶指针下移遍历
}
}
void PaveVeInfo(ListQueue Q){//查询便道车辆信息
if(Q.front->next == 0){
cout<<”便道上无车辆”<<endl;
Flag = 0;
}
while(Q.front->next != 0 && Flag){//便道非空
Cout<<VehicleID<<arriveTime<<endl;
Q.front->next = Q.front->next->next;//后移遍历
}
}
3.主要功能函数的程序流程图
图 2 程序流程图
五、测试结果
输入 | 输出 | |
停车场容量n(正整数) | 1.负数 | ERROR!请输入一个正整数 |
2.0 | ||
3.小数 | ||
4.正整数 | ---->输入停车费用 | |
停车场停车费用Price | 1.负数 | ERROR!请输入一个非负数 |
2.0 | ---->功能菜单选择 | |
3.小数 | ||
4.正整数 | ||
功能菜单选择choose | 1.负数 | ERROR!请输入1-4的整数 |
2.0 | ||
3.小数 | ||
4.>4的正整数 | ||
5.1 | ---->汽车进出停车场 | |
6.2 | ---->停车场基本信息 | |
7.3 | ---->停车场内车辆信息 | |
8.4 | ---->便道车辆信息 | |
汽车进出停车场 I/O/E | 1.除I/O/E外的字符 | ERROR!状态错误,请输入I进站/O出站/E退出 |
2.I/O/E | ---->车牌号 | |
车牌号 | 1.负数 | ERROR!车牌号格式错误,请输入正整数 |
2.0 | ||
3.小数 | ||
4.正整数 | ---->到站/出站时间 | |
到站/出站时间 | 1.<0和>24的数 | ERROR!时间格式错误,请输入0-24之间的整数 |
2.0-24的小数 | ||
3.0-24的整数 | 汽车的停留时间,计费 | |
其他 | 当(I输入次数-O的输入次数)>n时 | 停车场已满,汽车在便道的位置为: |
状态为O时,若输入的车牌号未出现过 | 停车场内无该车辆 |
六、完整代码
#define NULL 0
#define OK 1
#include<stdio.h>
#include<iostream>
#define pavementTime 0
using namespace std;
int position = 0;
//定义顺序栈(停车场)
typedef struct
{
double VehicleID[10];//车牌号
double arriveTime[10];//到达时间
int top;//栈指针
int size;//栈容量
}SqStack;
//定义链队列(便道)
typedef struct QNode
{
double VehicleID;//车牌号
double arriveTime;//到达时间
struct QNode *next;//指针域
}QNode,*QueuePtr;
typedef struct
{
QueuePtr front;//队头指针
QueuePtr rear;//队尾指针
}LinkQueue;
//初始化栈
void InitStack(SqStack &S,int n)
{
S.top = -1;//初始值为-1
S.size = n;//容量
}
//入栈
void Push(SqStack &S,double VehicleID,double arriveTime)
{
S.top++;
S.VehicleID[S.top] = VehicleID;
S.arriveTime[S.top] = arriveTime;
}
//出栈
void Pop(SqStack &S,double &VehicleID,double &arriveTime)
{
VehicleID = S.VehicleID[S.top];
arriveTime = S.arriveTime[S.top];
S.top--;
}
//判断栈空
int StackEmpty(SqStack S)
{
if(S.top == -1) return 1;//栈顶指针为-1则栈空
else return 0;
}
//判断栈满
int StackFull(SqStack S)
{
if(S.top == S.size - 1) return 1;//栈顶指针为栈容量-1则栈满
else return 0;
}
//初始化队列
void InitQueue(LinkQueue &Q)
{
Q.front=Q.rear=new QNode;//生成新节点作为头节点,队头和队尾指针指向此节点
Q.front->next = NULL;//头节点的指针域置空
}
//入队
void EnQueue(LinkQueue &Q,double VehicleID,double arriveTime)
{
QueuePtr p = new QNode;//为入队元素分配节点空间,用指针p指向
p->VehicleID = VehicleID;//记录车牌号
p->arriveTime = arriveTime;//记录到达时间
p->next = NULL;//新节点的指针域置空
Q.rear->next = p;//将新节点插入队尾
Q.rear = p;//修改队尾指针
position++;//记录队列位置,入队列+1
}
//出队
void DeQueue(LinkQueue &Q,double &VehicleID,double &arriveTime)
{
QueuePtr p = new QNode;//指定一个新的辅助节点p
p = Q.front->next;//p指向队头元素
VehicleID = p->VehicleID;//返回记录的车牌号
arriveTime = p->arriveTime;//返回记录的到达时间
Q.front->next = p->next;//修改头节点的指针域
if(Q.rear == p) Q.rear = Q.front;//最后一个元素被删,队尾指针指向头节点
delete p;//释放原队头元素的空间
position--;//记录队列位置,出队列-1
}
//判断队空
int QueueEmpty(LinkQueue Q)
{
if(Q.front == Q.rear) return 1;//队头指针与队尾指针重合
else return 0;
}
//停车场管理程序模拟逻辑实现
//汽车进出停车场
void IOVehicle(SqStack &S,SqStack &s,LinkQueue &Q,double Price)//S为停车场 ,s为临时车道,Q为便道
{
double arriveTime,VehicleID;
char state;//进出站状态
cout<<"请输入车的状态(I进站/O出站),车牌号,I/O时间(输入E 0 0结束):"<<endl;
cin>>state>>VehicleID>>arriveTime;
while(state!='I' && state!='O' && state!='E'){
cout<<"ERROR!状态错误,请输入I进站/O出站/E退出"<<endl;
cin>>state>>VehicleID>>arriveTime;
}
while(VehicleID<0 || (int)VehicleID!=VehicleID){
cout<<"ERROR!车牌号格式错误,请输入正整数"<<endl;
cin>>state>>VehicleID>>arriveTime;
}
while((arriveTime<0 || arriveTime>24) || (int)arriveTime!=arriveTime){
cout<<"ERROR!时间格式错误,请输入0-24之间的整数"<<endl;
cin>>state>>VehicleID>>arriveTime;
}
while(state != 'E'){
double leaveTime = arriveTime;//离开的时间
if(state == 'I'){//如果进站
if(!StackFull(S)){//如果栈未满
Push(S,VehicleID,arriveTime);//入栈
cout<<"汽车:"<<VehicleID<<"在停车场的位置为:"<<S.top+1<<endl;
}
else{
EnQueue(Q,VehicleID,pavementTime);//进入便道
cout<<"停车场已满,汽车:"<<VehicleID<<"在便道的位置为:"<<position<<endl;
}
}
else if(state == 'O'){
int possess = 0;//判断是否有该车信息的标志
int isTop = 0;//判断该车后方是否有车
for(int i=0;i<=S.top;i++){//循环查找
if(S.VehicleID[i] == VehicleID){ //如果有该车信息
possess = 1;
break;//跳出循环
}
}
if(!possess) cout<<"停车场内无车牌号为:"<<VehicleID<<" 的车辆"<<endl;
for(int j=S.top;j>=0;j--){
if(!possess) break;//如果无该车信息,跳出循环
if(S.VehicleID[j]!=VehicleID){//如果有该车信息,循环遍历匹配,若匹配失败
Pop(S,VehicleID,arriveTime);//出栈让路
Push(s,VehicleID,arriveTime);//进入临时车道
if(S.top == 0){//如果只有一辆车
isTop = 1;
break;//跳出循环
}
}
else{//匹配成功
isTop = 1;
break;//跳出循环
}
}
if(isTop){//若后方无车辆
Pop(S,VehicleID,arriveTime);//则直接出栈
cout<<"汽车:"<<VehicleID<<"停留时间为:"<<(leaveTime - arriveTime)<<"小时,共花费:"<<Price * (leaveTime - arriveTime)<<"元。"<<endl;
while(!StackEmpty(s)){//临时车道非空时
Pop(s,VehicleID,arriveTime);//退出临时车道
Push(S,VehicleID,arriveTime);//依次回到停车场
}
if(!QueueEmpty(Q)){//如果便道上有车
DeQueue(Q,VehicleID,arriveTime);//便道上的车离开便道
Push(S,VehicleID,arriveTime); //进入停车场
}
}
}
cin>>state>>VehicleID>>arriveTime;
while(state!='I' && state!='O' && state!='E'){
cout<<"ERROR!状态错误,请输入I进站/O出站/E退出"<<endl;
cin>>state>>VehicleID>>arriveTime;
}
while(VehicleID<0 || (int)VehicleID!=VehicleID){
cout<<"ERROR!车牌号格式错误,请输入正整数"<<endl;
cin>>state>>VehicleID>>arriveTime;
}
while((arriveTime<0 || arriveTime>24) || (int)arriveTime!=arriveTime){
cout<<"ERROR!时间格式错误,请输入0-24之间的整数"<<endl;
cin>>state>>VehicleID>>arriveTime;
}
}
}
//停车场信息
void parkInformation(SqStack S,int n,double Price) {
cout<<"停车场容量为:"<<n<<endl;
cout<<"停车场停车价格为:"<<Price<<" 元/时"<<endl;
cout<<"停车场车位余量:"<<n-S.top-1<<endl;
}
//停车场车辆信息
void ParkVeInfo(SqStack S) {
int i=S.top;
int have=1;
if(i==-1){
have=0;
cout<<"\n停车场内无车辆\n";
}
cout<<"-----------------------------------------\n"
<<" 汽车号码牌 | 汽车到达时间 \n";
while((i!=-1) && have) {
cout<<" "<<S.VehicleID[i]<<" | "<<S.arriveTime[i]<<endl;
i--;
}
cout<<"-----------------------------------------\n\n";
}
//便道车辆信息
void paveVeInfo(LinkQueue Q) {
QueuePtr p=Q.front->next;
int have=1;
if(p==NULL){
have=0;
cout<<"\n便道上无车辆\n";
}
cout<<"-----------------------\n"
<<"| 汽车号码牌 |\n";
while((p!=NULL) && have) {
cout<<"| "<<p->VehicleID<<" |"<<endl;
p=p->next;
}
cout<<"-----------------------\n\n";
}
//功能菜单系统
void Initialization() {
cout<<"*** 停车场管理系统功能界面 ***\n"
<<"* 1.汽车进入/退出停车场 *\n"
<<"* 2.显示停车场基本信息 *\n"
<<"* 3.查询停车场内车辆信息 *\n"
<<"* 4.查询便道车辆信息 *\n"
<<"******************************\n";
}
//主程序
int main()
{
double n,Price,choose;
cout<<"请输入停车场的容量:"<<endl;
cin>>n;
while(n<=0 || int(n)!=n){
cout<<"ERROR!请输入正整数"<<endl;
cin>>n;
}
cout<<"请输入停车场停车价格(元/时):"<<endl;
cin>>Price;
while(Price<0){
cout<<"ERROR!请输入一个正数"<<endl;
cin>>Price;
}
Initialization();
SqStack S,s;//停车场和临时车道
LinkQueue Q;//便道
InitStack(S,n);
InitStack(s,n);
InitQueue(Q);
while(true) {
cout<<"\n请选择功能\n";
cin>>choose;
while((int)choose!=1 && (int)choose!=2 && (int)choose!=3 && (int)choose!=4 || (int)choose!=choose){
cout<<"请输入1-4之间的数字"<<endl;
cin>>choose;
}
switch((int)choose) {
case 1: {
IOVehicle(S,s,Q,Price);//汽车进出停车场
break;
}
case 2: {
parkInformation(S,n,Price);//停车场基本信息
break;
}
case 3: {
ParkVeInfo(S);//停车场车辆信息
break;
}
case 4: {
paveVeInfo(Q);//便道车辆信息
break;
}
}
}
return 0;
}