说明:该程序设计采用常见基础的数据结构栈和队列实现了一个简单停车场管理系统。在具体设计中,实现了系统页面和停车场的示意图显示,通过调用顺序栈和链队的相关函数,模拟了实际停车场的运营流程。
目录
1 任务内容
任务描述:设停车场(如下图所示)内只有一个可停放几量汽车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停放在车场的最北端),若车场内已经停满几量汽车,则后来的汽车只能在门外的便道上等候,一旦停车场内有车开走,则排在便道上的第一辆汽车即可开入;当停车场内某车辆要离开时,由于停车场是狭长的通道,在它之后开入车场的车辆必须先退出车场为它让路,待该车辆开出大门外后,为它让路的车辆再按原次序进入车场。在这里假设汽车不能从便道上开走。试设计一个停车场管理程序(这里只是一个假想的停车场管理,并不代表实际的停车场管理)。
分析提示:汽车在停车场内进出是按照栈的运算方式来实现的,先到的先进停车场;停车场的汽车离开停车场时,汽车场内其它汽车为该辆汽车让路,也是按栈的方式进行;汽车在便道上等候是按队列的方式进行的。因此,将停车场设计成一个栈,汽车让路也需要另一个栈来协助完成,汽车进出便道用队列来实现。
基本要求:
1)接受命令和车号,若是汽车要进停车场,先判断停车场栈是否满,若不满,则汽车入栈,否则汽车进入便道队列等候。
2)若是汽车要离开停车场,为给汽车让路,将停车场栈上若干辆汽车入临时栈,等这辆车出停车场后,临时栈中的汽车出栈,在回到停车场栈,然后看便道队列是否为空,若不空则说明有汽车等候,从队头取出汽车号,让该车进入停车场栈。
3)重复1),2)直到为退出命令(车号为0或负数)。
数据结构:本设计中,栈采用顺序栈结构,队列用链式存储结构。
核心知识:栈和队列。
2 需求分析
2.1 功能需求
一、界面设计
1. 停车场管理系统界面
2. 停车场字符模拟示意图
2. 便道字符模拟示意图
二、停车场管理
1. 车辆停放:包括车辆停放操作、便道等候操作
2. 车辆离开:包括车辆离开操作、便道车辆停放操作
3. 停车场状态:显示当前停车场和便道的车辆状态
4. 打印停车场车辆信息:显示当前停车场示意图
5. 打印便道车辆信息:显示当前便道示意图
2.2 输入输出需求
一、系统界面
输出:“欢迎使用STRANGEX-03停车场管理系统”字样、停车场管理功能模块等内容。
输入:单个字符“A”“B”“C”等内容表示要选择的功能模块或退出系统的操作。
输出:执行对应功能模块的相关操作。
二、车辆停放模块(在系统界面输入A)
输出:当前停车场和便道的车辆状态,提示字样如“当前空余车位为X,便道上共有X辆车在等待,您确定要停车吗”。
(一)同意停放车辆
输入:单个字符“Y”表示同意。
输出:“请输入您的车辆编号”字样
输入:5位整型数字表示车辆编号
输出:“您的车辆已停放到停车场”或“您的车辆正在便道等待”
(二)拒绝停放车辆
输入:单个字符“N”表示拒绝。
输出:返回系统界面
三、车辆离开模块(在系统界面输入B)
输出:提示字样如“请输入您的车辆编号”
输入:5位整型数字表示车辆编号
(一)便道上没有车辆
输出:执行操作后提示“该车辆已离开,X车辆已停入停车场,便道现有X辆车在等待”,
(二)便道上有车辆
输出:“该车辆已离开停车场”
四、停车场状态模块(在系统界面输入C)
输出:当前停车场和便道的车辆状态,字样如“停车场共有%d个车位,当前空余车位为%d,便道上共有%d辆车在等待”
五、停车场车辆信息模块(在系统界面输入D)
输出:当前停车场的模拟示意图
六、便道车辆信息模块(在系统界面输入E)
输出:当前便道的模拟示意图
3 概要设计
3.1 抽象数据类型
本程序共设计三个抽象数据类型分别表示停车场栈、通道车辆结点和便道队列。
//停车场栈
typedef struct{
int data[StackSize];
int top;
} SqStack;
//通道车辆结点
typedef struct linked_queue{
int data;
struct linked_queue *next;
} DataNode;
//便道队列
typedef struct{
DataNode *front;
DataNode *rear ;
} LinkQuNode;
3.2 具体功能函数
本程序共有22个功能函数,具体包括4个界面设计函数、5个停车场管理函数、7个栈操作函数、6个队列操作函数。
//界面设计函数
void MainMenu(); //主菜单界面
void TouchMenu(SqStack *&s,LinkQuNode *&q); //菜单触控操作
void ParkingLot(SqStack *s); //停车场模拟界面
void WaitingRoad(LinkQuNode *&q); //便道模拟界面
//停车场管理函数
void ToPark(SqStack *&s,LinkQuNode *&q); //车辆停放操作
void ToLeave(SqStack *&s,LinkQuNode *&q); //车辆离开操作
void GetStatus(SqStack *s,LinkQuNode *q); //显示当前停车场和便道状态
void GetParking(SqStack *s); //打印当前停车场车辆信息
void GetWaiting(LinkQuNode *&q); //打印当前便道车辆信息
//栈操作函数
void InitStack(SqStack *&s); //初始化栈
void DestroyStack(SqStack *&s); //销毁栈
bool StackEmpty(SqStack *s); //判断栈是否为空
bool Push(SqStack *&s,int e); //入栈操作
bool Pop(SqStack *&s,int &e); //出栈操作
bool GetTop(SqStack *s,int &e); //获取栈顶元素
int CountStack(SqStack *s); //计算栈内元素个数
//队列操作函数
void InitQueue(LinkQuNode *&q); //初始化队列
void DestroyQueue(LinkQuNode *&q); //销毁队列
bool QueueEmpty(LinkQuNode *q); //判断队列是否为空
bool enQueue(LinkQuNode *&q,int e); //入队操作
bool deQueue(LinkQuNode *&q,int &e); //出队操作
int CountQueue(LinkQuNode *q); //计算队列内元素个数
4 详细代码
#include<bits/stdc++.h>
using namespace std;
const int StackSize=10;
//抽象数据类型
//停车场栈
typedef struct{
int data[StackSize];
int top;
} SqStack;
//便道车辆结点
typedef struct linked_queue{
int data;
struct linked_queue *next;
} DataNode;
//通道队列
typedef struct{
DataNode *front;
DataNode *rear ;
} LinkQuNode;
//具体功能函数列表
//界面设计函数
void MainMenu();
void TouchMenu(SqStack *&s,LinkQuNode *&q);
void ParkingLot(SqStack *s);
void WaitingRoad(LinkQuNode *&q);
//停车场管理函数
void ToPark(SqStack *&s,LinkQuNode *&q);
void ToLeave(SqStack *&s,LinkQuNode *&q);
void GetStatus(SqStack *s,LinkQuNode *q);
void GetParking(SqStack *s);
void GetWaiting(LinkQuNode *&q);
//栈操作函数
void InitStack(SqStack *&s);
void DestroyStack(SqStack *&s);
bool StackEmpty(SqStack *s);
bool Push(SqStack *&s,int e);
bool Pop(SqStack *&s,int &e);
bool GetTop(SqStack *s,int &e);
int CountStack(SqStack *s);
//队列操作函数
void InitQueue(LinkQuNode *&q);
void DestroyQueue(LinkQuNode *&q);
bool QueueEmpty(LinkQuNode *q);
bool enQueue(LinkQuNode *&q,int e);
bool deQueue(LinkQuNode *&q,int &e);
int CountQueue(LinkQuNode *q);
int main(){
SqStack *park;//定义停车场栈
LinkQuNode *wait;//定义通道队列
InitStack(park);
InitQueue(wait);
//调试专用数据
Push(park,12345);
Push(park,67890);
Push(park,63465);
Push(park,89986);
Push(park,53845);
Push(park,65374);
Push(park,15555);
Push(park,25389);
Push(park,24389);
TouchMenu(park,wait);
return 0;
}
//主菜单页面
void MainMenu(){
printf(" * * * * * * * * * * * * * * * * * * *\n");
printf(" * 欢迎使用STRANGEX-03停车场管理系统 *\n");
printf(" * * * * * * * * * * * * * * * * * * *\n");
printf(" * [A]车辆停放模块 *\n");
printf(" * [B]车辆离开模块 *\n");
printf(" * [C]显示当前停车场运营状态 *\n");
printf(" * [D]打印停车场内的车辆信息 *\n");
printf(" * [E]打印便道上的车辆信息 *\n");
printf(" * [Z]退出系统 *\n");
printf(" * * * * * * * * * * * * * * * * * * *\n");
printf("请输入字母选择你要使用的功能模块:");
}
//菜单触控
void TouchMenu(SqStack *&s,LinkQuNode *&q){
char c;
MainMenu();
while(scanf("%c",&c)){
switch(c){
case 'A':
ToPark(s,q);
MainMenu();
break;
case 'B':
ToLeave(s,q);
MainMenu();
break;
case 'C':
GetStatus(s,q);
MainMenu();
break;
case 'D':
GetParking(s);
MainMenu();
break;
case 'E':
GetWaiting(q);
MainMenu();
break;
case 'Z':
printf("\n欢迎再次使用STRANGEX-03停车场管理系统,再见!");
return;
default:
printf("请输入正确的字母:");
}
c=getchar();//消除回车对程序的影响
}
}
//停车场模拟界面
void ParkingLot(SqStack *s){
printf(" @ @ @ @ @ @ @ ↑\n");
for(int i=0;i<StackSize;i++){
printf(" @ ");
if(i<CountStack(s)){
printf("车辆%d",s->data[i]);
printf(" @");
}
else{
printf(" @");
}
if(i==0){
printf(" 北");
}
else if(i==StackSize-2){
printf(" ↓");
}
else if(i==StackSize-1){
printf(" 南");
}
else if(i==StackSize/2-1){
printf(" 停车场示意图");
}
printf("\n");
}
}
//便道模拟界面
void WaitingRoad(LinkQuNode *&q){
printf(" ");
for(int i=0;i<CountQueue(q);i++){
printf("@ @ @ @ @ @ ");
}
printf("@ @\n");
printf(" 出口 ← ");
DataNode *car=q->front;
int k=0;
if(car!=NULL){
while(car->next!=NULL){
printf(" | 车辆%d",car->data);
car=car->next;
}
printf(" | 车辆%d | ",car->data);
}
else {
printf(" ");
}
printf(" ← 入口 便道示意图\n");
printf(" ");
for(int i=0;i<CountQueue(q);i++){
printf("@ @ @ @ @ @ ");
}
printf("@ @\n");
}
//车辆停放
void ToPark(SqStack *&s,LinkQuNode *&q){
printf("\n※当前功能模块:[A]车辆停放模块\n");
printf("---------------------------------------------------------------------\n");
printf("当前空余车位为%d,便道上共有%d辆车在等待,您确定要停车吗?\n",StackSize-CountStack(s),CountQueue(q));
int c;
printf("请输入[Y/N]:");
scanf("%c",&c);
c=getchar();
if(c=='Y'){
int carNo;
printf("请输入车辆编号:");
scanf("%d",&carNo);
if(Push(s,carNo)){
printf("车辆%d已成功停放在停车场\n",carNo);
}
else{
enQueue(q,carNo);
printf("停车场已满,车辆%d正在便道上等候\n",carNo);
}
}
else if(c=='N'){
printf("您已确认不停车,自动返回主菜单\n");
}
else if(c!='N') {
printf("输入错误,自动返回主菜单\n");
}
printf("---------------------------------------------------------------------\n");
printf("\n");
return;
}
//车辆离开
void ToLeave(SqStack *&s,LinkQuNode *&q){
printf("\n※当前功能模块:[B]车辆离开模块\n");
printf("---------------------------------------------------------------------\n");
int carNo;
int No=-1;
printf("请输入您的车辆编号:");
scanf("%d",&carNo);
for(int i=0;i<CountStack(s);i++){
if(carNo==s->data[i]){
No=i;
break;
}
}
if(No==-1){
printf("对不起,没有找到您的车辆,自动返回主菜单\n");
}
else {
SqStack *temp;
int e;
InitStack(temp);
int x=CountStack(s);
for(int i=x-1;i>No;i--){
Pop(s,e);
Push(temp,e);
}
Pop(s,e);
for(int i=x-1;i>No;i--){
Pop(temp,e);
Push(s,e);
}
if(!QueueEmpty(q)){
deQueue(q,e);
Push(s,e);
printf("车辆%d已离开,车辆%d已成功停放在停车场,便道还有%d辆车在等待\n",carNo,e,CountQueue(q));
}
else {
printf("车辆%d已离开停车场\n",carNo);
}
}
printf("---------------------------------------------------------------------\n");
printf("\n");
return;
}
//停车场状态
void GetStatus(SqStack *s,LinkQuNode *q){
printf("\n※当前功能模块:[C]显示当前停车场运营状态\n");
printf("---------------------------------------------------------------------\n");
printf("停车场共有%d个车位,当前空余车位为%d,便道上共有%d辆车在等待\n",StackSize,StackSize-CountStack(s),CountQueue(q));
printf("---------------------------------------------------------------------\n");
printf("\n");
return;
}
//打印停车场车辆信息
void GetParking(SqStack *s){
printf("\n※当前功能模块:[D]打印停车场内的车辆信息\n");
printf("---------------------------------------------------------------------\n");
ParkingLot(s);
printf("---------------------------------------------------------------------\n");
printf("\n");
}
//打印便道车辆信息
void GetWaiting(LinkQuNode *&q){
printf("\n※当前功能模块:[E]打印便道上的车辆信息\n");
printf("---------------------------------------------------------------------\n");
WaitingRoad(q);
printf("---------------------------------------------------------------------\n");
printf("\n");
}
//栈操作函数
//初始化栈
void InitStack(SqStack *&s){
s=(SqStack *)malloc(sizeof(SqStack));
s->top=-1;
}
//销毁栈
void DestroyStack(SqStack *&s){
free(s);
}
//判断栈是否为空
bool StackEmpty(SqStack *s){
return (s->top==-1);
}
//进栈
bool Push(SqStack *&s,int e){
if(s->top==StackSize-1)
return false;
s->top++;
s->data[s->top]=e;
return true;
}
//出栈
bool Pop(SqStack *&s,int &e){
if(s->top==-1)
return false;
e=s->data[s->top];
s->top--;
return true;
}
//取栈顶元素
bool GetTop(SqStack *s,int &e){
if(s->top==-1)
return false;
e=s->data[s->top];
return true;
}
//返回栈的元素个数
int CountStack(SqStack *s){
return s->top+1;
}
//队列操作函数
//初始化
void InitQueue(LinkQuNode *&q){
q=(LinkQuNode *)malloc(sizeof(LinkQuNode));
q->front=q->rear=NULL;
}
//销毁队列
void DestroyQueue(LinkQuNode *&q){
DataNode *pre=q->front,*p;
if(pre!=NULL){
p=pre->next;
while(p!=NULL){
free(pre);
pre=p;
p=p->next;
}
free(pre);
}
free(q);
}
//判断队列是否为空
bool QueueEmpty(LinkQuNode *q){
return q->rear==NULL;
}
//进队列
bool enQueue(LinkQuNode *&q,int e){
DataNode *p;
p=(DataNode *)malloc(sizeof(DataNode));
p->data=e;
p->next=NULL;
if(q->rear==NULL)
q->front=q->rear=p;
else{
q->rear->next=p;
q->rear=p;
}
return true;
}
//出队列
bool deQueue(LinkQuNode *&q,int &e){
DataNode *t;
if(q->rear==NULL)
return false;
t=q->front;
if(q->front==q->rear)
q->front=q->rear=NULL;
else
q->front=q->front->next;
e=t->data;
free(t);
return true;
}
//返回队列的元素个数
int CountQueue(LinkQuNode *q){
int sum=1;
DataNode *a=q->front,*b=q->rear;
if(a==NULL&&a==b)
return 0;
while(a!=b){
sum++;
a=a->next;
}
return sum;
}
5 使用说明
系统界面共有五个功能选项和一个退出系统选项,选择不同选项根据提示进入下一步操作:
选择[A]:进入车辆停放模块。
选择[B]:进入车辆离开模块。
选择[C]:进入显示当前停车场运营状态模块。
选择[D]:进入打印停车场内的车辆信息模块。
选择[E]:进入打印便道上的车辆信息模块。
选择[Z]:显示“欢迎再次使用STRANGEX-03停车场管理系统,再见!”并退出系统,结束程序。
6 测试结果与分析
为便于调试显示,前期对停车场栈进行以下操作,存入部分数据。
Push(park,12345);
Push(park,25345);
Push(park,67890);
Push(park,89986);
Push(park,53845);
Push(park,65374);
Push(park,15555);
Push(park,25389);
Push(park,24389);
输入数据 | 调试截图 |
A Y 54321 | |
A Y 89745 | |
A Y 88888 | |
C | |
D | |
E | |
B 54321 | |
E | |
Z |
7 总结感悟
在完成栈和队列知识梳理后进行本次程序设计,进一步巩固了对栈和队列的理解。题目本身难度不大,主要就根据任务的意思模拟了相关操作就能实现。
此次设计中主要遇到的一个比较大的问题是,无法实现向栈和队列中添加string类型数据,运行到相关Push操作和enQueue操作时提示“Thread 1 received signal SIGSEGV, segmentation fault.”,也就导致了标识车辆时只能使用整型数字表示车辆编号,而无法使用string字符串(即模拟车牌号)进行标识。这个问题目前仍未解决,网上也找不到相关的资料,可待后续再研究一下。
本次为了提升对于栈和队列应用的理解,没有使用C++内置的STL栈和队列。但其实对于相关的函数可以使用类进行封装,此前在Java中学习了面向对象的相关知识,但在C++中还未实现过,这也是后续可以学习实践的方向。