数据结构课程设计停车场管理系统.docx
《数据结构课程设计停车场管理系统.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计停车场管理系统.docx(25页珍藏版)》请在冰豆网上搜索。
数据结构课程设计停车场管理系统
课程设计报告
课程名称《数据结构》
课题名称数据结构综合实训
专业计算机科学与技术
班级计算机1581
学号
姓名
指导教师
2017年6月10日
湖南工程学院
课程设计任务书
课程名称数据结构
课题数据结构综合实训
专业班级
学生姓名
学号
指导老师
审批
任务书下达日期2017年6月10日
任务完成日期2017年6月23日
一、设计内容与设计要求
1.设计内容:
[问题描述1] 设停车场是一个可停放n辆汽车的狭长通道,且只有一个大门可供汽车进出。
汽车在停车场内按车辆到达时间的先后顺序,依次从停车厂最里面向大门口停放(最先到达的第一辆车停放在车场的最里面),若车场内一停满n辆汽车,则后来的汽车只能在门外的便道上等候,一旦有车开走,则排在便道上的第一辆车即可开入;当停车场内某辆车要离开时,在它之后进入的车辆必须先退出车场为它让路,待该辆车开出大门外,其他车辆再按原次序进入车场,每辆停放在车场内的车在它离开时必须按它停留时间长短交纳费用。
如果停留在便道上的车未进车场就要离去,允许其离去,不收停车费,并且其他在便道上等待的车辆的次序不变试设计这样一个停车场模拟管理程序。
[基本功能1]
(1)单个车辆入站。
当系统正常投入运行后,会有零散的车辆进进出出,因此,设计一个函数实现单个车辆入站。
(2)车站内信息实时显示。
车站内信息包括两个部分:
停车场内停放的车辆以及在外面通道上等停的车辆。
(3)车辆出站。
当停车场内车辆出站后,检查通道上是否有车等停,如果有,则要把排在最前面的车调入停车场内。
(4)如果有车辆离去,计算其停车费用。
[问题描述2] Huffman编码是一种最优变长码,即带权路径最小。
这种编码有很强的应用背景,是数据压缩中的一个重要理论依据。
对输入的一串文字符号实现Huffman编码,再对Huffman编码生成的代码串进行译码,输出电文字符串。
[基本功能2]
1).针对给定的字符串,建立Huffman树。
2).生成Huffman编码。
3).对编码文件译码。
2.设计要求:
1).设计正确,方案合理。
2).界面友好,使用方便。
3).程序精炼,结构清晰。
4).设计报告5000字以上,含程序设计说明、系统的功能框图、流程图、源程序清单等。
5).实际操作过程中遇到的问题及解决方法:
设计总结及心得体会。
6).上机演示。
二、进度安排
第15周星期六8时:
30分——11时:
30分
星期日8时:
30分——11时:
30分
第17周星期二8时:
30分——11时:
30分
星期三19时:
00分——22时:
00分
星期四8时:
30分——11时:
30分
第18周星期一19时:
00分——22时:
00分
星期二8时:
30分——11时:
30分
星期三8时:
30分——11时:
30分
一、停车场管理系统
1、需求分析
设停车场是一个可停放n辆汽车的狭长通道,且只有一个大门可供汽车进出。
汽车在停车场内按车辆到达时间的先后顺序,依次从停车厂最里面向大门口停放(最先到达的第一辆车停放在车场的最里面),若车场内一停满n辆汽车,则后来的汽车只能在门外的便道上等候,一旦有车开走,则排在便道上的第一辆车即可开入;当停车场内某辆车要离开时,在它之后进入的车辆必须先退出车场为它让路,待该辆车开出大门外,其他车辆再按原次序进入车场,每辆停放在车场内的车在它离开时必须按它停留时间长短交纳费用。
如果停留在便道上的车未进车场就要离去,允许其离去,不收停车费,并且其他在便道上等待的车辆的次序不变试设计这样一个停车场模拟管理程序。
●程序的功能
1)车辆入站时,该程序能够实现单个车辆入站。
2)能够实时显示停车场内停放的车辆以及在外面通道上等停的车辆。
3)当停车场内车辆出站后,该程序能够检查通道上是否有车等停,如果有,则把排在最前面的车调入停车场内。
4)能够通过停车时长来计算其停车的费用。
●输入输出的要求
车辆按顺序进入停车场内,当车辆出站时输出停车的费用,实时显示通道和停车场内的车辆信息。
2、概要设计
程序分为主函数main函数、结构体部分和功能函数部分。
该程序定义了两个结构体:
停车场,栈结构:
SqStack包含两个信息,车牌号CarNo进场时间CarTime;便道,队列结构:
SqQueue包含一个信息,车牌号CarNo。
他们的结构体分别如下:
typedefstruct{
intCarNo[N];//车牌号
intCarTime[N];//进场时间
inttop;//栈指针
}SqStack;//定义停车场结构体顺序栈类型
typedefstruct{
intCarNo[M];//车牌号
intfront,rear;//队首和队尾指针
}SqQueue;//定义便道结构体循环队类型
●程序中包含如下函数:
InitStack(SqStack*&s)//初始化栈s
StackEmpty(SqStack*s)//判断栈s是否为空栈
StackFull(SqStack*s)//判断栈s是否满
Push(SqStack*&s,inte1,inte2)//进栈一个元素
Pop(SqStack*&s,int&e1,int&e2)//出栈一个元素
DispStack(SqStack*s)//从栈顶到栈底输出元素信息
InitQueue(SqQueue*&q)//初始化队列q
QueueEmpty(SqQueue*q)//判断队列q是否为空
QueueFull(SqQueue*q)//判断队列q是否为满
enQueue(SqQueue*&q,inte)//进队一个元素
deQueue(SqQueue*&q,int&e)//出队一个元素
DispQueue(SqQueue*q)//输出队列中的元素信息
●Main函数和其他各部分结构关系如下:
图1.2.1函数结构图
3、详细设计
定义车牌号为整型,时间为整型,设定停车时间单价为2,程序分三个模块:
分别是车辆到达、车辆离开、屏幕显示,各模块算法如下:
图1.3.1停车场整体模块图
●到达模块:
到达时有两种情况,即车辆是否满,未满则直接进入停车场,若满,则在便道上等待。
算法分析图如下:
图1.3.2到达模块
●离开模块:
当车辆离开时,车库为空时,提示没有车,结束;否则车辆离开。
分析图如下:
图1.3.3离开模块
●显示模块:
显示模块有两个显示选项,停车场与便道,结构图如下:
图1.3.4显示模块
4、调试分析以及设计体会
●数据测试:
选择1,车辆进入停车场,录入车辆信息,如图1.4.1录入车辆
图1.4.1录入车辆
由图1.4.1可以看出该停车场只能停3辆车,停车场内停满后,车辆在便道内等候,演示图如下:
图1.4.2停车上限
车辆出站,当信息输错时提示“未找到该编号的汽车”。
图1.4.3错误提示
车辆出站时按时间计费。
图1.4.4计费
显示停车场和候车场中的车辆。
图1.4.5显示
选择离开时如果输入候车场中的车辆信息会提示没有该辆车,因为候车场中的车是随时可以走的,无需记录扣费。
图1.4.6候车场(便道)
测试完毕,选择退出时自动显示停车场和候车场中的车辆信息。
图1.4.7退出界面
当输入信息格式错误时会进入无限循环,界面如图1.4.8所以输入时要严格按照格式进行输入,稍有错误便要重新输入,很是麻烦。
图1.4.8格式输入错误的后果
解决方案:
严格按照格式进行输入
●测试结果分析和体会:
此停车管理系统基本可以实现一个小的停车场的管理,其“到达”与“离开“方法都相对比较完整,以及结算清单明了,尽管在时间先后上有出现混乱,但当其用到实际应用时,那个时间先后就可以避免了。
但在输入数据时,要严格按照格式进行输入,否则有可能出现死去或崩溃,若本系统能加上保存功能就更好了,因为一个系统在使用过程中总会关机等,而此系统的缺点却是没有保存功能,关闭之后就要重新建立了,会慢慢完善。
二、哈夫曼编码
1、需求分析
Huffman编码是一种最优变长码,即带权路径最小。
这种编码有很强的应用背景,是数据压缩中的一个重要理论依据。
对输入的一串文字符号实现Huffman编码,再对Huffman编码生成的代码串进行译码,输出电文字符串。
●程序的功能
1).针对给定的字符串,建立Huffman树。
2).生成Huffman编码。
3).对编码文件译码。
●输入输出的要求
对输入的一串文字符号实现Huffman编码,再对Huffman编码生成的代码串进行译码,输出电文字符串。
2、概要设计
程序分为主函数main函数、结构体部分和功能函数部分
●该程序定义了两个结构体:
结构体HTNode包含节点值data[5]定义为字符型,权重值weight定义为整型,定义了双亲节点、左孩子和右孩子为整型,结构体如下所示:
typedefstruct{
chardata[5];//节点值
intweight;//权重
intparent;//双亲节点
intlchild;//左孩子节点
intrchild;//右孩子节点
}HTNode;
结构体HCode包含字符串cd[N]用于存放哈夫曼编码,结构体如下所示:
typedefstruct{
charcd[N];//存放哈夫曼码
intstart;
}HCode;
●该程序包含如下函数:
CreateHT(HTNodeht[],intn)//构造哈夫曼树
CreateHCode(HTNodeht[],HCodehcd[],intn)//构造哈夫曼编码
DispHCode(HTNodeht[],HCodehcd[],intn)//输出哈夫曼编码
●Main函数和其他各部分结构关系如下:
图2.2.1Main函数和其他函数关系
3、详细设计
●构造哈夫曼树CreateHT(HTNodeht[],intn)函数:
用ht[]数组存放哈夫曼树,对于具有n个叶子节点的哈夫曼树,总共有2n-1个节点。
其算法思路是:
先将所有2n-1个节点的parent、lchild和rchild域置为初值-1,处理每个非叶子节点ht[i](存放在ht[n]~ht[2n-2]中):
从ht[0]~ht[i-1]中找出根节点(即其parent域为-1)权值最小的两个节点ht[lnode]和ht[rnode],将它们作为ht[i]的左右子树,ht[lnode]和ht[rnode]的双亲节点置为ht[i],并且ht[i],Weight﹦ht[lnode]。
Weight+ht[rnode].weight。
如此操作直到所有n-1个非叶子节点处理完毕。
构造哈夫曼树的算法如下:
voidCreateHT(HTNodeht[],intn){
inti,k,lnode,rnode;
intmin1,min2;
for(i=0;i<2*n-1;i++)//所有节点的相关域置初值-1
ht[i].parent=ht[i].lchild=ht[i].rchild=-1;
//构造哈夫曼树
for(i=n;i<2*n-1;i++){
min1=min2=32767;//lnode和rnode为最小权重的两个节点位置
lnode=rnode=-1;
for(k=0;k<=i-1;k++)
//只在尚未构造二叉树的节点中查找
if(ht[k].parent==-1){
if(ht[k].weightmin2=min1;rnode=lnode;
min1=ht[k].weight;lnode=k;
}
elseif(ht[k].weightmin2=ht[k].weight;rnode=k;
}
}
ht[lnode].parent=i;ht[rnode].parent=i;
ht[i].weight=ht[lnode].weight+ht[rnode].weight;
ht[i].lchild=lnode;ht[i].rchild=rnode;
}
}
●构造哈夫曼编码CreateHCode(HTNodeht[],HCodehcd[],intn)函数:
由于哈夫曼树中每个叶子节点的哈夫曼编码长度不同,为此采用HCode类型变量的cd[start]~cd[n]存放当前节点的哈夫曼编码。
对于当前叶子节点ht[i],先将对应的哈夫曼编码hcd[i]的start域置初值n,找其双亲节点ht[f]。
若当前节点是其双亲节点的左孩子节点,则在hcd[i]的cd数组中添加0,若当前节点是其双亲节点的右孩子节点,则在hcd[i]的cd数组中添加1;然后将hcd[i]的start域减1。
再对其双亲节点进行同样的操作,如此操作直到无双亲节点即到达树根节点为止。
最后让start指向哈夫曼编码的开始字符。
根据哈夫曼树求对应的哈夫曼编码的算法如下:
voidCreateHCode(HTNodeht[],HCodehcd[],intn){
inti,f,c;
HCodehc;
//根据哈夫曼树求哈夫曼编码
for(i=0;ihc.start=n;c=i;
f=ht[i].parent;
//循序直到树根节点
while(f!
=-1){
if(ht[f].lchild==c)//处理左孩子节点
hc.cd[hc.start--]='0';
else//处理右孩子节点
hc.cd[hc.start--]='1';
c=f;f=ht[f].parent;
}
hc.start++;//start指向哈夫曼编码最开始字符
hcd[i]=hc;
}
}
●总的设计流程图如下:
图2.3.1设计流程
4、调试分析以及设计体会
●数据测试:
设定如下一组测试数据在main函数中:
单词
The
of
a
to
and
in
that
he
is
at
on
for
his
are
be
频度
1192
677
541
518
462
450
242
195
190
181
174
157
138
124
123
编译后测试运行,出现错误,错误界面如下:
图2.4.1错误界面
经过仔细排查,发现在DispHCode(HTNodeht[],HCodehcd[],intn)函数的for循环中i不能小于等于0,部分错误代码如下:
for(i=0;i<=n;i++){
j=0;
printf("%s:
\t",ht[i].data);
for(k=hcd[i].start;k<=n;k++){
printf("%c",hcd[i].cd[k]);
j++;
}
m+=ht[i].weight;
sum+=ht[i].weight*j;
printf("\n");
}//部分错误代码
把i<=n改为i更正错误后代码如下:
for(i=0;ij=0;
printf("%s:
\t",ht[i].data);
for(k=hcd[i].start;k<=n;k++){
printf("%c",hcd[i].cd[k]);
j++;
}
m+=ht[i].weight;
sum+=ht[i].weight*j;
printf("\n");
}//部分错误代码更正后的正确代码
错误更正后继续进行测试,编译运行:
图2.4.2正确界面
此次运行正常,测试结果正确。
●测试结果分析和体会:
利用哈夫曼编码可以对数据进行压缩,通常我们把数据压缩的过程称为编码,解压缩的过程称为解码。
电报通信是传递文字的二进制码形式的字符串。
但在信息传递时,总希望总长度尽可能最短,即采用最短码。
通过此次哈夫曼编码的课程设计,让我更熟练的运用树形的数据结构,更加深入的了解了哈夫曼编码的过程,在这个过程中虽然有一些小错误,小麻烦,但我通过查阅资料,逐一排查,最终把这些小问题一一解决。
三、总结
两周的课程设计很快就结束了,通过本次课程设计,让我对堆栈和队列以及二叉树有了更深的理解和操作能力。
我们的课程设计题目是停车场管理系统和哈夫曼编码。
刚开始做这个两个程序的时候,感到完全无从下手,甚至让我觉得完成这次程序设计根本就是不可能的,然后王老师说程序可以不用自己写,于是我们便开始查阅各种资料上XX,找到程序之后便开始理解两个程序,即使这样,理解起来还是有很多问题,通过仔细思考和询问同学最终弄清楚了。
通过此次停车场管理系统的课程设计,使我充分的理解了用栈和队列实现模拟停车场的基本原理,知道了栈的顺序存储结构和队列的链式存储结构的定义和算法描述,同时也学会了编写停车场问题的程序。
在做停车场管理系统的时候,刚开始因为对栈的知识理解不深透,理解别人的代码感觉非常困难,通过不停的复习课本上的知识点和不断的练习,终于完成了用栈实现停车场系统。
在做哈夫曼编码的程序时,我首先查阅了资料,了解了什么是哈夫曼编码,哈夫曼编码是一种编码方式,是可变字长编码的一种。
Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)。
然后又从书上找到了哈夫曼编码的代码,认真阅读代码并理解它后便把它抄了下来。
两个程序虽然都是从书上找的,但是在运行时还是出现了很多错误,之后又经过几次的修改,终于得出了正确结果。
这次课程设计终于顺利完成了,在这当中遇到了很多问题,最后在王老师和同学们的指导帮助下,终于顺利完成了课设,在本课程设计中,我明白了理论与实际应用相结合的重要性,在编程中,我意识到了自己动手能力的不足,虽然相比较大一而言进步很大,但是我还是不满意,毕竟代码不是自己写的,编程还必须依赖书本才能写出来,很少是自己写的。
在编程中我还认识到了,编程不能停下,如果编程的时间少了,知识忘的会很快,而且动手也会很慢。
写代码是一件长远的事情。
数据结构是一门比较难而且十分重要的课程。
需要多花时间上机练习。
虽然此次课程设计的代码不是我自己写的,但我能感觉到我的编程能力还是有所提高。
我清楚地意识到长时间编程的好处,俗话说“熟能生巧”,确实是这样。
如果我们长时间不编程,在一接触他,我们会感到很陌生。
有规律的编程会提高我们的动手能力,我们的思维,也会让我们变得很细心。
在答辩时,王老师告诉我们,编程的思维很重要,不能一味的死编程,那样不会有什么进步,要想提高编程能力,就要提高自己的编程思维;还有就是在写一个项目时,首先就是要有想法,有了想法程序代码自然而然就能写出来。
编程的想法很重要,王老师的这些指导对我的触动很大,谢谢老师。
此次课程设计完满结束了,总的来说,这次课程设计让我获益匪浅,对数据结构也有了进一步的理解和认识,学无止境,自已懂得的知识还只是凤毛棱角,我还会更加的努力深入的学习下去的。
附录(源程序)
●停车场管理系统
#include
#include
#defineN3//停车场内最多的停车数
#defineM4//候车场内最多的停车数
#definePrice2//每单位停车费用
typedefstruct{
intCarNo[N];//车牌号
intCarTime[N];//进场时间
inttop;//栈指针
}SqStack;//定义顺序栈类型
typedefstruct{
intCarNo[M];//车牌号
intfront,rear;//队首和队尾指针
}SqQueue;//定义循环队类型
//以下为顺序栈的基本运算算法
voidInitStack(SqStack*&s){
s=(SqStack*)malloc(sizeof(SqStack));
s->top=-1;
}
boolStackEmpty(SqStack*s){
return(s->top==-1);
}
boolStackFull(SqStack*s){
return(s->top==N-1);
}
boolPush(SqStack*&s,inte1,inte2){
if(s->top==N-1)
returnfalse;
s->top++;
s->CarNo[s->top]=e1;
s->CarTime[s->top]=e2;
returntrue;
}
boolPop(SqStack*&s,int&e1,int&e2){
if(s->top==-1)
returnfalse;
e1=s->CarNo[s->top];
e2=s->CarTime[s->top];
s->top--;
returntrue;
}
voidDispStack(SqStack*s){
inti;
for(i=s->top;i>=0;i--)
printf("%d",s->CarNo[i]);
printf("\n");
}
//以下为循环队列的基本运算算法
voidInitQueue(SqQueue*&q){
q=(SqQueue*)malloc(sizeof(SqQueue));
q->front=q->rear=0;
}
boolQueueEmpty(SqQueue*q){
return(q->front==q->rear);
}
//判断队满
boolQueueFull(SqQueue*q){
return((q->rear+1)%M==q->front);
}
//进队
boolenQueue(SqQueue*&q,inte){
if((q->rear+1)%M==q->front)//队满
returnfalse;
q->rear=(q->rear+1)%M;
q->CarNo[q->rear]=e;
returntrue;
}
//出队
booldeQueue(SqQueue*&q,int&