数据结构课程设计 停车场管理系统.docx
- 文档编号:9807560
- 上传时间:2023-02-06
- 格式:DOCX
- 页数:30
- 大小:381.36KB
数据结构课程设计 停车场管理系统.docx
《数据结构课程设计 停车场管理系统.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计 停车场管理系统.docx(30页珍藏版)》请在冰豆网上搜索。
数据结构课程设计停车场管理系统
停车场管理系统
1实习目的
通过实习,了解并初步掌握设计、实现较大系统的完整过程,包括系统分析、编码设计、系统集成、以及调试分析,熟练掌握数据结构的选择、设计、实现以及操作方法,为进一步的应用开发打好基础。
2问题描述
停车场是一条可以停放n辆车的狭窄通道,且只有一个大门汽车停放安到达时间的先后依次由北向南排列(大门在最南端,最先到达的第一辆车停在最北端)若停车场已经停满n辆车,后来的汽车在便道上等候,一旦有车开走,排在便道上的第一辆车可以开入;当停车场的某辆车要离开时,停在他后面的车要先后退为他让路,等它开出后其他车在按照原次序开入车场,每两停在车场的车要安时间长短缴费。
3需求分析
3.1设计思想
此停车场管理系统是在一个狭长的通道上的,而且只有一个大门可以供车辆进出,并且要实现停车场内某辆车要离开时,在它之后进入停车场的车都必须先退出停车场为它让路,待其开出停车场后,这些辆再依原来的次序进场的功能,就可以设计两个堆栈,其中一个堆栈用来模拟停车场,另一个堆栈用来模拟临时停车场,该临时停车场用来存放当有车辆离开时,原来停车场内为其让路的车辆。
至于当停车场已满时,需要停放车辆的通道可以用一个循环队列来实现。
当停车场内开走一辆车时,通道上便有一辆车进入停车场,此时只需要改变通道上车辆结点的连接方式就可以了,使通道上第一辆车进入停车场这个堆栈,并且使通道上原来的第二辆车成为通道上的第一辆车,此时只需将模拟通道的循环队列的头结点连到原来的第二辆车上就可以了。
这个程序的关键是车辆的进站和出站操作,以及车场和通道之间的相互关系。
由于车站是一个很窄的、一边开口的车道,先进后出,类似数据结构中的栈结构,故车场用栈这种数据结构来描述。
外面的狭长的通道,先进先出,故可用队列结构来描述。
考虑到车场和通道在整个程序中都要用到。
故把这两个变量定义成全局变量。
本程序中的数据对象是汽车,可以认为车牌号是每个元素的关键项,不能重复,和现实中一样,另外加了车主姓名这一数据项,为表简洁,其他相关信息如入场时间,车的类型,收取费率等,都不再考虑,具体应用的时候可以方便地修改得到。
3.2实现方法
对于此停车场管理系统的实现,就是用两个堆栈来分别模拟停车场以及停车场内车辆为其它车辆让路时退出停车的临时停放地点。
至于通道上车辆的停放则用一个循环队列来实现,此时,通道上车辆的离开或者进入停车场只需改变此循环队列上的结点而已。
4概要设计
4.1数据结构设计
第一个定义汽车的信息:
车牌号num[10]和车主姓名name[10]:
typedefstructcar{
charnum[10];
charname[10];
}Car;
第二个定义汽车场的结构,在这里我把它看成是一个栈,在这里定义栈的容量等信息:
typedefstruct{
Cardata[maxsize];
intn;//栈容量设定
inttop;
}Stack;//顺序栈用来存放汽车场内的车辆信息
第三个定义通道的结构,在这里我把它看成是一个循环队列,在这里定义队列胡容量等信息:
typedefstruct{
Cardata[maxsize];
intn;//队列容量设定
intnum;//当前通道上的车辆数
intfront,rear;
}Queue;//循环队列用来存放通道内的车辆信息
4.4函数及功能要求
1.intPush(Stack*S,Carx):
创建入栈的操作,以实现车辆进入停车场的操作
2.intPop(Stack*S,Car*px):
创建出栈的操作,以实现车辆离开停车场的操作
3.intInsertQueue(Queue*Q,Carx):
创建入队的操作,以实现进入临时停车场的操作
4.intDeleteQueue(Queue*Q,Car*x):
创建出队的操作,以实现离开临时停车场的操作
5.voidShowCar(void):
创建显示车站内信息的子程序。
6.voidInitCarpark(void):
创建车辆成批入站的子程序。
7.voidInsertCar(void):
创建单个车辆入站的子程序。
8.voidExitCar(void):
创建车辆出站的子程序。
9.Pop(SCar,&x);:
提供指定车辆出站的功能。
10.voidSetCar(void):
提供车站模拟系统相关功能设定的功能。
11.voidcarmenu(void):
显示出车站管理系统主菜单。
12.voidmain(void):
此为主函数,调用其他子程序。
5总体设计
5.1总体设计图
图2.1功能模块图
运行程序到系统界面,接着系统界面就会出现让你能选择的功能:
【1】车辆成批入站
【2】单个车辆入站
【3】车辆出站
【4】车站内信息实时显示
【5】相关功能设定
【0】退出本系统
5.2模块流程图
5.2.1车辆成批入站
图2.2车辆成批入站流程图
5.2.2车站内信息显示
图2.3停车场内信息显示流程图
6详细设计
6.1采用结构体定义的相关数据类型
前面提到,要用到栈和队列的操作。
这里,由于一个车场的最大容量是一定的,且车场最多执行的操作是插入和删除操作,所以用顺序储存结构可以带来更大益处。
为了防止队列中出现“假溢出”现象,这里采用了循环队列。
在模拟汽车这个对象时,进行了简化处理,只取得最核心的两个数据项:
车牌号和车主姓名。
具体数据结构定义如下:
首先定义maxsize为20:
#definemaxsize20
第二个再定义汽车的信息:
车牌号num[10]和车主姓名name[10]:
typedefstructcar{
charnum[10];
charname[10];
}Car;
第三个定义汽车场的结构,在这里我把它看成是一个栈,在这里定义栈的容量等信息:
typedefstruct{
Cardata[maxsize];
intn;//栈容量设定
inttop;
}Stack;//顺序栈用来存放汽车场内的车辆信息
第四个定义通道的结构,在这里我把它看成是一个循环队列,在这里定义队列胡容量等信息:
typedefstruct{
Cardata[maxsize];
intn;//队列容量设定
intnum;//当前通道上的车辆数
intfront,rear;
}Queue;//循环队列用来存放通道内的车辆信息
6.2功能函数设计
(1)车辆成批入站voidInitCarpark(void)//车辆成批入站
此函数也可以作为初始化车场的函数,因为一个车场刚开始投入运行的时候会有很多的车进来,这也是设计此函数最重要的一个原因。
每行输入一个汽车信息,最后结束的时候输入“##”即可。
汽车信息中前面表示汽车的车牌号,后面表示车主姓名,中间用空格隔开。
当输入汽车的数目超过规定的最大容量的时候(如果开始不设置最大容量,默认值为系统申请的最大值maxsize=20),自动检测条件,给出相关提示信息。
程序如下:
voidInitCarpark(void)//车辆成批入站
{charnum[8],*pnum,name[10],*pname;
Carpcar;
pnum=num;
pname=name;
printf("\n\n请输入车子的信息(包括车牌号和车主姓名(两者之间用空格隔开))(以'##'这个符号结束):
\n");
scanf("%s%s",pnum,pname);
while(strcmp(pnum,"#")!
=0)
{strcpy(pcar.num,pnum);
strcpy(pcar.name,pname);
if(Push(SCar,pcar)==-1)
{printf("\n车站已满!
车辆已经入通道!
\n");
if(InsertQueue(QCar,pcar)==-1)
printf("\n通道已满,进入通道失败!
!
\n");
}
scanf("%s%s",pnum,pname);
}
printf("这批汽车已经成功进入停车场\n");
getch();
carmenu();
}
(2)单个车辆入站voidInsertCar(void)//单个车辆入站
当系统正常投入运行后,会有零散的车辆进进出出,如还用成批输入方式的话,将会带来一定的麻烦。
此函数具有函数InitCarpark()几乎所有的功能,程序跟InitCarpark()这个差不多,同样先输入,然后再判断停车场是否满了,通道是否满了,最后执行结果,程序如下:
voidInsertCar(void)//单个车辆入站
{charnum[10],*pnum,name[10],*pname;
Carpcar;
pnum=num;
pname=name;
printf("\n\n请输入车子的信息(包括车牌号和车主姓名(两者之间用空格隔开)):
\n");
scanf("%s%s",pnum,pname);
strcpy(pcar.num,pnum);
strcpy(pcar.name,pname);
if(Push(SCar,pcar)==-1)
{printf("\n车站已满!
车辆已经入通道!
\n");
if(InsertQueue(QCar,pcar)==-1)
printf("\n通道已满,进入通道失败!
\n");
getch();
}
(3)车辆内信息显示函数voidShowCar(void)//车站内信息显示
如果车场本身是空的,没有汽车,那么也就不存在查看汽车信息了。
故本函数一开始进行合理性检查,如果条件不成立,拒绝执行显示信息操作,给出出错的信息后返回到主界面。
前面提到,车站内信息包括两部分:
车场内停放的车辆,在外面通道上等停的车辆。
因为通道上也不一定有车,程序输出车场内的所有汽车信息后,自动进行判断通道上是否有车辆。
如果有车辆的话,继续输出停在通道上的车子信息。
程序如下:
voidShowCar(void)//车站内信息显示
{inti,front,rear;
if(SCar->top==-1)
{printf("\n\n这停车场是空的!
\n");getch();carmenu();}
printf("\n\n目前停车场的车有:
\n---车牌号-----------车主姓名\n");
for(i=0;i
{printf("%-13s",SCar->data[i].num);
printf("%18s\n",SCar->data[i].name);}
if(QCar->rear!
=QCar->front)//通道内有车辆
{front=QCar->front;rear=QCar->rear;
printf("\n通道信息:
\n---车牌号--------------车主姓名\n");
while(front!
=rear)
{printf("%-13s",QCar->data[front].num);
printf("%18s\n",QCar->data[front].name);
front=(front+1)%QCar->n;}
}
}
(4)车辆出站函数voidExitCar(void)//车辆出站
同上,首先进行和利息你给检查。
这里的检查包括两个部分:
车场非空且输入的车牌号在车场中。
如果一切条件满足,则执行推车操作。
最后,检查通道上是否有车辆等待。
如果通道不为空,程序会自动把排在通道最前面的车调入车场内。
其中,退车的算法过程如下:
前面检测条件满足时,执行如下操作:
由于车场很窄,当一辆车要出场时,排在它后面的车辆需要先出场,等要退出的车开走后,刚才为它让道的那些车再按原次序进入车场。
不难看出,这里需要创建一个临时栈,用于保存让道车辆的信息。
在前面的合理性检查中,已经定位到出场车辆所在位置,从栈顶开始,到所在位置前一个结束,车场内执行出栈操作,临时栈结构执行入栈操作。
在当前位置执行出栈操作,即可实现指定的车辆出场。
当临时栈不为空时,依次执行:
临时栈退栈,车场内入栈。
(5)车站模拟系统相关功能设定函数voidSetCar(void)//车站模拟系统相关功能设定
此函数很简单,首先用一个do-while循环,得到一个合理值,修改相关参数即可。
这里有一个防错设计:
当输入的最大容量小于车场内当前的车辆数时,拒绝执行修改。
程序如下:
voidSetCar(void)//车站模拟系统相关功能设定
{intb;
printf("选择1:
修改停车场的容量\n");
printf("选择2:
修改通道的容量\n");
printf("请你选择操作(1-2):
\n");
scanf("%d",&b);/*读入选择*/
if(b==1)
{intn,flag=1;
printf("\n\n目前停车场最大的容纳量是:
%d\n",SCar->n);
printf("\n输入您想要的停车场的最大容纳量:
(<=%d)\n",maxsize);
do{printf("请输入数值:
");
scanf("%d",&n);
if(n>maxsize){printf("输入错误,请重新输入\n");}
if(n
{flag=0;
n=SCar->n;
break;
}
}while(n<0||n>maxsize);
SCar->n=n;
if(flag!
=0)printf("\n修改成功!
\n");
else
printf("\n错误!
车站车辆已经超过此数!
如要再输,请再按功能5\n");
getch();
carmenu();}
if(b==2)
{intn,flag=1;
printf("\n\n目前通道最大的容纳量是:
%d\n",QCar->n-1);
printf("\n请输入您想要的通道的最大容纳量:
(<=%d)\n",maxsize);
do{printf("请输入数值:
");
scanf("%d",&n);
if(n>maxsize){printf("输入错误,请重新输入\n");}
if(n
{flag=0;
n=QCar->n;
break;
}
}while(n<0||n>maxsize);
QCar->n=n+1;
if(flag!
=0)printf("\n修改成功!
\n");
else
printf("\n错误!
车站车辆已经超过此数!
如要再输,请再按功能5\n");
getch();
carmenu();}}
(6)车站管理系统主菜单函数voidcarmenu(void)//车站管理系统主菜单
此函数是用户与系统之间的一个窗口,用户通过它来选择相关操作。
用printf语句打印出供选择项目后,用不会显的getch()得到一个字符,用开关语句switch进行分类,判断用户想要执行的操作,然后执行相关功能函数即可。
(7)主函数voidmain(void)
为分别表示车场和通道的两个指针变量申请空间,分别调用相应的初始化函数,得到一个合理解,然后程序流向主供选菜单,供用户选择执行。
voidmain(void)
{if((SCar=(Stack*)malloc(sizeof(Stack)))==NULL)
{printf("Failed!
");exit
(1);}
if((QCar=(Queue*)malloc(sizeof(Queue)))==NULL)
{printf("Failed!
");exit
(1);}
InitStack(SCar);InitQueue(QCar);
carmenu();exit(0);
}
7系统测试及其结果
7.1程序调试中的问题
调试过程中的主要问题
由于此停车场管理系统是分模块设计的,而且在程序的实现过程中又使用了清屏函数,所以,运行时用户选择任务并且执行完任务后,又会回到供用户选择功能的主界面,因此整个程序从整体上来讲结构清晰,使用方便。
本程序的调试运行,总体上情况良好,但中间也出现了一些小问题。
其中比较有代表性的主要问题有:
(1)当停车场已经达到最大容量,但仍有车辆进入停车场的时候,运行界面上没有出现或者说出现了但又跳掉了“车站已满!
车辆已经入通道!
”的提示信息。
在查阅了多种资料后,在那一个printf语句后加了一个getch(),此时,程序运行结果就符合要求了,看起来也比较清晰了。
(2)使用getch()语句必须使用头文件#include
刚开始因为没有使用这个头文件,所以会出现getch()这个无法辨别
图4.1错误报告1
(3)在对字符型的数据进行赋值的时候,要用strcpy,而不能直接用pcar.num=pnum这样的赋值形式,这样子会产生如下的错误:
图4.2错误报告2
正确的形式应该是这样的:
strcpy(pcar.num,pnum);
(4)同时,对字符型的数据进行比较的时候,也需要用strcmp。
不过我认为用while(pnum=="#")的形式也是可以的,我试验了一下,结果是可以的,所以不用strcmp这个东西也是可以的。
注意呀,那个#符号必须加””号,不加的话就有四个错误了:
图4.3错误报告3
(5)把通道看成是一个队列,但在通道中的车辆数目总是少一辆,刚开始总是感觉疑问,明明就是设定maxsize为20的,通道内的车辆为什么就只有19辆呢,后来,我突然想到原来队列的Q->front是不存放数据的,终于找到了错误的地方了,所以我在定义数列的地方,把原来的Q->n=maxsize改成了Q->n=maxsize+1;结果是对的了。
(6)采用清屏的功能:
system("cls");/*运行前清屏*/
刚开始不知道有这个功能,在屏幕执行的时候,总感觉屏幕非常的复杂杂乱,感觉不是很舒服,后来问了同学一下,发现了这个功能,就马上加上了这个功能,屏幕就看起来比较清晰和舒服了。
(7)刚开始的时候,程序的健壮性不是很强,在主菜单函数中选择case多少时,如果不是规定的数字范围内的时候,它就会直接说按任意键返回。
所以为了增强程序的健壮性,在最后加上default:
ShowCar()这句话,在一开始运行程序的时候,由于此时停车场内信息没有输入,认为是空的,而当用户选择了退出车站的时候,程序将给出出错的信息“这停车场是空的”。
(8)在结构化程序设计中一般不主张使用goto语句,以免造成程序流程的混乱,使理解和调试程序都产生困难,所以尽量少用goto语句。
因为在网上看到了这段话,所以我就把那个车站模拟系统相关功能设定这个模块改成用do-while语句的形式,其实我觉得do-while语句还是比较容易能实现的,而且程序也比较容易去检测出错误。
(9)对于通道的假定,原本是没有采用循环队列的,只是采用了比较基本简单的顺序存储队列,后来发现,这样子会发生“假溢出”的现象,所谓的“假溢出”顾名思义就是队列出现了“假满”的情况,而不是“真满”,比如设队头指针为front,队尾指针是rear,约定front指向队头元素的前一位置,rear指向队尾元素。
当front等于-1时队空,rear等于m-1时为队满。
由于队列的性质(“删除”在队头而“插入”在队尾),所以当队尾指针rear等于m-1时,若front不等于-1,则队列中仍有空闲单元,所以队列并不是真满。
这时若再有入队操作,会造成假“溢出”。
7.2结果截图
7.2.1车辆成批入站
待主界面显示出来后,按1进入输入车辆的界面,然后输入你想输入的车辆信息,然后以“##”号结束;在此之前,你还可以先设定车站和通道的容量;如下图:
1:
先修改停车场与通道的容量,都改成2;
图4.1先修改停车场与通道的容量截图
2:
成批输入三辆汽车的信息,因为停车场内只能停两辆汽车,所以第三辆车要停放在通道上等停,一旦停车场内有汽车开走,通道上的车辆即可进入;
图4.2车辆成批入站结果截图
3:
待返回主界面后,按4,即会显示出车站内与通道上的车辆信息;
图4.3车辆成批入站结果截图
7.2.2车辆出站
1:
输入想要出站的汽车牌号,然后汽车出站,接着通道上的第一辆汽车进入停车场;
图4.4车辆出结果截图
(1)
2:
通道内的车已经进入停车场,如下图:
图4.5车辆出结果截图
8心得体会
通过这次的课程设计,我拓宽了知识面,锻炼了能力。
比如对于队列的队满或者队空的状态呀,或者队列的长度呀,记得我那时想了好久的一个问题,我在上面程序的调试分析里有提过,就是我明明定义maxsize等于20,可是通道内汽车的数量却只能输进19辆汽车的信息,我纠结了好久,后来,我的脑袋中突然闪过一个循环队列的图,那个Q->front好像是不存放数据资料的,这个Q->front这个结点确实是不存放数据的,这样子一想,问题就游刃而解了,只要把原来的Q->n=maxsize改成了Q->n=maxsize+1就可以了。
也许这就是课程设计的目的吧,在于把理论和实际相结合吧,把课堂上所学到的系统化的理论知识投到实际中,巩固还没有巩固的知识点,也有助于我们提高观察,分析和解决问题的实际工作能力,就像那时我和赵老师在对问题进行分析时,因为双方对汽车场通道的看法都是不同的,所以我们就进行讨论了,我觉得能和老师讨论这很重要,特别是能找出程序上的不足,对完善我们的程序有着莫大的帮助,那天下午,我也改进了程序,在程序上加上了一个选择,就是停车场和通道的容量,可以由你更改,改变原来的默认值,但唯一的前提是不能比默认值大。
可以说吧,《数据结构》真的也比较难,特别是知识点非常的多,很容易看那个忘记了这个,对于课设要用到的综合知识,那可是难上加上,不过,这也才激发了我的兴趣,有动力比别人早完成程序。
很开心我做到了,既完成了课设也学到了好多知识,经历了这一个星期,我收获了如下的几点:
1.程序的设计思想的精巧的重要性,是不管怎么说都不为过的,好的程序可以让大家很快的明白你的思想,而且很方便的来实现它。
还有不管这程序有多长,只要你解释了之后,别人很快就能明白,看程序也比较简单了。
2.《数据结构》是一门实践性较强的课程,为了学好这门课程,必须在掌握理论知识的同时,加强上机实践。
一个人的力量是有限的,要想把课程设计做的更好,就要学会参考一定的资料,要善于捕获资料,吸取别人的经验,让自己和别人的思想有机的结合起来,得出属于你自己的灵感。
3.学会“递进”的思想:
程序的编写需要有耐心,有些事情看起来很复杂,但问题需要一点一点去解决,分析问题,把问题一个一个划分,划分成小块以后就逐个去解决。
再总体解决大的问题。
这样做起来不仅有条理也使问题得到了轻松的解决。
这次的程序训练培养了我实际分析问题、编程和动手能力,使我掌握了程序设计的基本技能,提高了我适应实际,实践编程的能力。
这次的课程设计我对于专业课的学习有了更加深刻的认识,以为现在学的知识用不上就加以怠慢,等到想用的时候却发现自己的学习原来是那么的不扎实。
以后努力学好每门专业课,让自己拥有更多的知识,才能解决更多的问题!
总的来说,这次课程设计让我获益匪浅,对数据结构也有了进一步的理解和认识,也让我相信,只要你要做(justdoit),没有什么困难能难倒我们……
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构课程设计 停车场管理系统 数据结构 课程设计 停车场 管理 系统