【摘要】:伴随着科技的飞速发展,交通工具的越来越普及。汽车作为人类社会中最主要的交通工具之一,起着重大作用。随着人们生活水平的提高,汽车的数量也与日俱增,于是停车正在成为世界性的问题。以前落后的人力停车管理即将被高科技化的自动停车管理系统所取代,高度自动化的停车场管理系统节省了大量时间和人力物资消耗,大大提高了效率。
本论文介绍了一种停车场管理系统模型。它能在任意时间内,根据有效的停车空间,计算能够停泊的车辆数量,并且使用自动而可靠的完成车辆的进。还能够显示是否有停放的场地以及是否有车辆进、出停车场。
因此,停车场管理系统的研究和实现具有十分重要的现实意义。
3-1 开发环境和开发工具
3-1-1 程序设计语言简介:
C语言的基本概念:
源文件:源文件即源程序代码文件,C语言源文件后缀名是.c;
头文件:头文件的后缀名为.h,C语言代码由源文件和头文件构成;
关键字:关键字是C语言已经定义好的一些字,这些字在C语言中代表着一些特殊含义,我们必须搞懂每个关键字的所有含义和用法,否则就看不懂C语言程序;
注释:C语言中的注释一般以//开头,或者/* */,注释是给程序员看的,编译器编译程序的时候是忽略注释内容的,所以机器根本看不见注释,也不理注释;
符号:C语言中包含很多符号,如; : , + - * / () [] {} 等等,每个符号都有自己的含义,必须理解它们的含义才能看懂C语言程序;
变量:可以发生变化的量。C语言程序中用变量来进行计算;
函数:函数是C语言的一个基本组成单位,一个C语言程序其实就是由一个或多个函数组成的,每个函数用来完成某项功能,函数也可以调用别的函数来完成其功能。函数的标志是()。C语言中有一个特殊的函数叫main(),这个函数是整个程序内定的入口,也就是说整个C语言程序是从main()函数开始执行的,其他的函数都是直接或者间接被main()调用的。
C语言的特性:
1.有穷性:一个算法应包含有限的操作步骤而不能是无限的。
2.确定性:算法中每一个步骤应当是确定的,而不能应当是含糊的、模棱两可的。
3.有零个或多个输入。
4.有一个或多个输出。
有效性:算法中每一个步骤应当能有效地执行,并得到确定的结果。
C语言的数据类型:
(1) 整型:C语言中的整型对应数学中的整数,整型变量是用来描述一个整数值的,整型变量经过计算后也只能是整数(整型),不可能出现小数(浮点型)。
C语言中整形有三种:
int 整型
short int 短整型,可简写为short
long int 长整型,可简写为long
(2) 浮点型:C语言中的浮点型对应数学中的小数。浮点型有float和double两种,使用方式相同,而表示的范围和精度不同。
float表示的范围小,精度低(小数点后6位),而double表示范围大,精度高。(小数点后16位)。
注:printf中打印float或double类型,是用%f,而不是%d。
(3) 字符型:字符型对应ASCII字符。ASCII字符是一种编码,就是用数字编码来表示一个符号的一种方法,本质上说,字符型其实也是整型,只是这些整型数被用来表示一些字符的ASCII码值,所以叫做字符型。
字符型一般用8位二进制表示,无符号字符型范围是0~255;
(4) 有符号数和无符号数:数学中的数都是有符号的,即有正数和负数之分。所以计算机中的数据类型也有符号,分为有符号数和无符数。
C语言的常用运算符:
(1) 数学运算符:
与数学中意义相同:加减乘除,取余,括号
与数学中的意义不同:= 赋值运算符,不同于数学中的等号。赋值运算符的作用是经过运算后符号左边(左值,一般是一个变量)的值等于右边(右值,一般是常数或变量)的值了。
(2) 判断运算符
== 等于
! = 不等于
(3) 逗号运算符:主要是用来分割。**
3-1-2 开发背景:
近年来,随着经济建设的快速发展,汽车带给人们快乐的同时也带来了越来越突出的难题:城市交通问题日益严重,停车问题接踵而至,一个不到10平方米的停车位,牵动着社会的“神经”,停车场车位不足的问题越来越突出。目前,有偿使用停车场是这个问题最为有效的解决方式,这就使得停车场管理的重要性越来越受到重视。然而目前的大部分停车场管理系统都是采取人工判别车型、人工收费、人工放行以及人工引导车辆入库等比较传统的管理模式,这在很大程度上制约着城市的发展。
3-1-3 开发环境:
DEV C++;
3-2 设计思想:
3-2-1 系统需求分析:
设停车场内只有一个可停放n辆汽车的狭长通道,且只有一个大门可供汽车进出。汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停放在车场的最北端),若车场内已停满n辆汽车,则后来的汽车只能在门外的便道上等候,一旦有车开走,则排在便道上的第一辆车即可开入;当停车场内某辆车要离开时,在它之后开入的车辆必须先退出车场为它让路,待该辆车开出大门外,其它车辆再按原次序进入车场,每辆停放在车场的车在它离开停车场时必须按它停留的时间长短交纳费用。
3-2-2 系统总体设计:
1 以栈模拟停车场,以队列模拟车场外的便道,按照从终端读入的输入数据序列进行模拟管理。
2 每一组输入数据包括三个数据项:汽车“到达”或“离去”信息、汽车牌照号码及到达或离去的时刻.
3 对每一组输入数据进行操作后的输出数据为:若是车辆到达,则输出汽车在停车场内或便道上的停车位置;若是车离去;则输出汽车在停车场内停留的时间和应交纳的费用(在便道上停留的时间不收费)。栈以顺序结构实现,队列以链表实现。
4 需另设一个栈,临时停放为给要离去的汽车让路而从停车场退出来的汽车,也用顺序存储结构实现。输入数据按到达或离去的时刻有序。栈中每个元素表示一辆汽车,包含两个数据项:汽车的牌照号码和进入停车场的时刻.
3-2-3 算法思想描述:
该系统需要构建两个顺序栈,一个链栈,分别表示停车场,临时停车点,候车场。
○1当车进入停车场时:
首先,记录车牌号和时间,并输出;
其次,观察停车场是否已满(StackFull() 方法):
如果停车场不满,则车进入停车场(Push() 方法),输出停泊位置;
如果停车场满,观察候车场(QueueFull()方法):如果候车场不满,车进入候车场,输出该车在候车场的位置;否则,候车场停满,该车只能离开。
*○2当车离开停车场时:
首先,记录车牌号和时间,并输出;
其次,在已有的车牌号里搜索刚被记录的车牌号(for循环):
如果找不到:输出“未找到该编号的车”,
如果找到:不停的从停车场中退出车辆Pop(),进入到临时栈中Push()。
直到那个想要出去的汽车离开。
然后,计算该车的停车费用((time-e2)Price)。
之后,该车离开后,退出去的车从临时栈退回停车场:从临时栈退出车辆,进入停车场中,直到临时栈为空。
最后,若此时,候车场又停了车辆,则车从候车场进入到停车场中,直到候车场为空。
○3显示停车场情况:
判断停车场是否为空(StackEmpty()),若为空,则输出“停车场中无车辆”,若不空,则输出停车场中的车辆。
○4显示候车场的情况:
判断候车场是否为空(Isempty ()),若为空,则输出“候车场中无车辆”,若不空,则输出侯车场中的车辆。
5结束。
3-3 算法实现
3-3-1 数据结构:
数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。通常情况下,精心选择的数据结构可以带来更高的运行或者存储效率。
栈:是只能在某一端插入和删除的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。分为顺序栈和链栈,本题用的是顺序栈。
队列:是种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列是按照“先进先出”或“后进后出”的原则组织数据的。队列中没有元素时,称为空队列。队列分为循环队列和链队,本题用的是链队。
3-3-2 程序模块:
在主函数之前:
1. 相关头文件的调用和说明:
#include<stdio.h>
#include<stdlib.h>//函数库
#define TRUE 1
#define FALSE 0
#define N 10 //停车场最多停车数
#define M 10 //候车场最多停车数
#define Price 2 //每单位时间停车费用
- 结构体的定义:
顺序栈和链队的结构体的定义
typedef struct
{
int carnum[N]; //车牌号,其中N指的是车牌的数量,等价于停车的数量,从0~(N-1)个
int time[N];//进入时间
int top;//停车位置,栈顶指针
}Seqstack;//顺序栈
typedef struct Node
{
int data;//车牌号码
struct Node* next;//指针域
}linkqueuenode;//链队结点
typedef struct
{
linkqueuenode * front;//结点类型的队头指针
linkqueuenode * rear;//结点类型的队尾指针
}linkqueue;//链队
3.各个方法的定义:
顺序栈的基本方法定义:
1.初始化:
void Init(Seqstack *S)//使用了一个顺序栈指针型的变量S,指针型变量可以操作地址,有时更加方便
{
S->top=-1; //这里用的是“->”而不是 “.”了,这就是指针型和其他类型的区别之一
}
2.进栈:
int Push(Seqstack *S, int e1,int e2)//进栈,压入
{
if(S->top==N-1)//表示栈已满
return FALSE;
else
{
S->top++;//栈顶指针先往上移一位,第一次从-1到0
S->carnum[S->top]=e1;// 车牌号
S->time[S->top]=e2;//时间
return TRUE;
}
}
3.出栈:
出栈时,首先判断当前栈是否为空,如果为空,则出栈时则会发生下溢。
int Pop(Seqstack *S,int *e1,int *e2) //出栈,弹出
{
if(S->top==-1)//空栈时无法再删除
return FALSE;
else
{
*e1=S->carnum[S->top];//车牌号码
*e2=S->time[S->top];//时间
S->top--;//栈顶指针下移一位
return TRUE;
}
}
4.判断栈空栈满
int StackEmpty(Seqstack *S)//栈空
{
return(S->top==-1);
}
int StackFull(Seqstack *S)//栈满
{
return(S->top==N-1);
}
5.打印数据
void Printstack(Seqstack *S)//打印数据
{
for(int i=0;i<=S->top;i++)//循环输出
{
printf("%d ",S->carnum[i]);
}
printf("\n");
}
链栈的基本方法定义:
1.初始化:
int Init(linkqueue *Q)//初始化
{
Q->front=(linkqueue *)malloc(sizeof(linkqueue));//为头结点指针申请分配空间
if(Q->front!=NULL)//申请成功
{
Q->rear=Q->front;/*只为头结点分配空间,那么,这个链队列只是一个带头结点的空链表,
尾指针也指向头结点 */
Q->front->next=NULL;//空队列的头结点指针域为空
return TRUE;
}
else
return FALSE;//申请空间失败
}
2.入队
int Enterqueue(linkqueue *Q, int x)//这里的x是需要在主函数里输入的
{
linkqueuenode * temp;
temp=(linkqueuenode *)malloc(sizeof(linkqueuenode));
if(temp!=NULL)
{
temp->data=x;//车牌号
temp->next=NULL;
Q->rear->next=temp;//尾指针的指针域指向新指针
Q->rear=temp;//尾指针移动 ,成为最末尾
return TRUE;
}
else
return FALSE;
}
3.出队
int Deletequeue(linkqueue *Q ,int *x)//出队首先要判断的是队列是否为空
{
linkqueuenode *temp;
if(Q->front==Q->rear)
{
printf("队列为空!");
return FALSE;
}
else
{
temp=Q->front->next;//首元结点
*x=temp->data;//将车牌号给*x
Q->front->next=temp->next;//队头元素出列
if(Q->rear ==temp)
{
Q->rear=Q->front;
}
free(temp);//释放存储空间
return TRUE;
}
}
主函数:
1.定义变量,为结点申请空间:
int com;
int no,e1,time,e2;
int i,j,t;
Seqstack *St,*St1; //St是停车场,St1是临时停放为给要离去的汽车让路而从停车场退出来的汽车
linkqueue Qu; //Qu是候车场
St=(Seqstack *)malloc(sizeof(Seqstack ));//申请空间
St1=(Seqstack *)malloc(sizeof(Seqstack ));//申请空间
(&Qu)->front=(linkqueuenode *)malloc(sizeof(linkqueuenode));//为头结点指针申请分配空间
2.调用初始化函数:
Init(St);
Init(St1);
Initqueue(Qu);
3.输出一个选择框:
printf ("\t********************************************************\n");
printf ("\t---------------Welcome to our Car Parking-------------\n");
printf ("\t* 1.车辆进入 *\n");
printf ("\t* 2.车辆离开 *\n");
printf ("\t* 3.显示停车场情况 *\n");
printf ("\t* 4.显示候车场情况 *\n");
printf ("\t* 5.输入的命令错误 *\n");
printf ("\t-----------------------------------------------------\n");
- do语句执行各种函数:
流程图:
case 1: 车辆进入
case 1: /*汽车到达*/
printf("输入车牌号和时间: ");
scanf("%d %d",&no,&time);
if (!StackFull(St)) /*停车场不满*/
{
Push(St,no,time);//进入停车场
printf(" >>停车场位置:%d\n",St->top+1);
}
else /*停车场满*/
{
if (!QueueFull(&Qu)) /*候车场不满*/
{
Enterqueue(&Qu,no);
printf(" >>候车场位置:%d\n",(&Qu)->rear);
}
else
printf(" >>候车场已满,不能停车\n");
}
break;
case 2: 车辆离开
case 2: /*汽车离开*/
printf("输入车牌号和时间: ");
scanf("%d%d",&no,&time);
for (i=0; i<=St->top && St->carnum[i]!=no; i++); //在栈中找
if (i>St->top)
printf(" >>未找到该编号的汽车\n");
else
{
t = St->top - i; //需要出栈的车辆数目
for (j=0; j<t; j++) //不停的从停车场的栈中退出车辆,进入到临时栈St1
{
Pop(St,&e1,&e2);
Push(St1,e1,e2); //e1和e2都是从Pop()方法中得到的
}
Pop(St,&e1,&e2); //那个想要出去的汽车,离开
printf(" >>车牌号为%d的汽车停车费用为:%d\n",no,(time-e2)*Price);
while (!StackEmpty(St1)) /*将临时栈St1重新回到St中*/
{
Pop(St1,&e1,&e2);
Push(St,e1,e2);
}
if (!Isempty(&Qu)) /*队不空时,将队头进栈St*/
{
Deletequeue(&Qu,&e1);
Push(St,e1,time); /*以当前时间开始计费*/
}
}
break;
case 3.4: 停车场和候车场的情况
case 3: /*显示停车场情况*/
if (!StackEmpty(St))
{
printf(" >>停车场中的车辆:"); /*输出停车场中的车辆*/
Printstack(St);
}
else
printf(" >>停车场中无车辆\n");
break;
case 4: /*显示候车场情况*/
if (!Isempty(&Qu))
{
printf(" >>候车场中的车辆:"); /*输出候车场中的车辆*/
Printqueue(&Qu);
}
else
printf(" >>候车场中无车辆\n");
break;
case 5:输入的命令错误
case 0: /*结束*/
if (!StackEmpty(St))
{
printf(" >>停车场中的车辆:"); /*输出停车场中的车辆*/
Printstack(St);
}
if (!Isempty(&Qu))
{
printf(" >>候车场中的车辆:"); /*输出候车场中的车辆*/
Printqueue(&Qu);
}
break;
3-3-3 各模块之间的调用关系:
主函数调用各个函数:
3-3-4 源程序代码:
#include<stdio.h>
#include<stdlib.h>
#define TRUE 1
#define FALSE 0
#define N 10 //停车场最多停车数
#define M 10 //候车场最多停车数
#define Price 2 //每单位时间停车费用
/*定义存储结构*/
typedef struct
{
int carnum[N]; //车牌号,其中N指的是车牌的数量,等价于停车的数量,从0~(N-1)个
int time[N];//进入时间
int top;//停车位置,栈顶指针
}Seqstack;//顺序栈
typedef struct Node
{
int data;//车牌号码
struct Node* next;//指针域
}linkqueuenode;//链队结点
typedef struct
{
linkqueuenode * front;//结点类型的队头指针
linkqueuenode * rear;//结点类型的队尾指针
}linkqueue;//链队
/*顺序栈的方法定义*/
void Init(Seqstack *S)//初始化
{
S->top=-1;
}
int StackEmpty(Seqstack *S)//栈空
{
return(S->top==-1);
}
int StackFull(Seqstack *S)//栈满
{
return(S->top==N-1);
}
int Push(Seqstack *S, int e1,int e2)//进栈,压入
{
if(S->top==N-1)//表示栈已满
return FALSE;
else
{
S->top++;//栈顶指针先往上移一位,第一次从-1到0
S->carnum[S->top]=e1;// 车牌号
S->time[S->top]=e2;//时间
return TRUE;
}
}
int Pop(Seqstack *S,int *e1,int *e2) //出栈,弹出
{
if(S->top==-1)//空栈时无法再删除
return FALSE;
else
{
*e1=S->carnum[S->top];//车牌号码
*e2=S->time[S->top];//时间
S->top--;//栈顶指针下移一位
return TRUE;
}
}
void Printstack(Seqstack *S)//打印数据
{
for(int i=0;i<=S->top;i++)//循环输出
{
printf("%d ",S->carnum[i]);
}
printf("\n");
}
/*链队的方法*/
int Initqueue(linkqueue &Q)//初始化
{
if((&Q)->front!=NULL)//申请成功
{
(&Q)->front=(linkqueuenode *)malloc(sizeof(linkqueuenode));//为头结点指针申请分配空间
(&Q)->rear=(&Q)->front;/*只为头结点分配空间,那么,这个链队列只是一个带头结点的空链表,
尾指针也指向头结点 */
(&Q)->front->next=NULL;//空队列的头结点指针域为空
return TRUE;
}
else
return FALSE;
}
int Enterqueue(linkqueue *Q, int x)//这里的x是需要在主函数里输入的
{
linkqueuenode * temp;
temp=(linkqueuenode *)malloc(sizeof(linkqueuenode));
if(temp!=NULL)
{
temp->data=x;//车牌号
temp->next=NULL; //
Q->rear->next=temp;//尾指针的指针域指向新指针
Q->rear=temp;//尾指针移动 ,成为最末尾
return TRUE;
}
else
return FALSE;
}
int Deletequeue(linkqueue *Q ,int *x)//出队首先要判断的是队列是否为空
{
linkqueuenode *temp;
if(Q->front == Q->rear)
{
printf("队列为空!");
return FALSE;
}
else
{
temp=Q->front->next;
*x=temp->data;//将车牌号给*x
Q->front->next=temp->next;//队头元素出列
if(Q->rear==temp)
{
Q->rear=Q->front;
}
free(temp);//释放存储空间
return TRUE;
}
}
int Isempty(linkqueue *Q)
{
if(Q->rear==Q->front)
{
return TRUE;
}
else
return FALSE;
}
int QueueFull(linkqueue *Q)//这个队满的情况就是意味着链队的长度到达了M
{
int i=0;
linkqueuenode *temp;
temp=Q->front->next;
while(temp!=NULL)
{
i++;
temp=temp->next;
}
if(i>=M)
{
return TRUE;
}
else
{
return FALSE;
}
}
int Printqueue(linkqueue *Q)//输出
{
linkqueuenode *temp;
temp=Q->front->next;
if(temp==NULL)
{
return FALSE;
}
else
{
while(temp!=NULL)
{
printf("%d ",temp->data);
temp=temp->next;
}
printf("\n");
return TRUE;
}
}
/*main函数用于模拟停车场运转*/
int main()
{
int com;
int no,e1,time,e2;
int i,j,t;
Seqstack *St,*St1; //St是停车场,St1是临时停放为给要离去的汽车让路而从停车场退出来的汽车
linkqueue Qu; //Qu是候车场
St=(Seqstack *)malloc(sizeof(Seqstack ));//申请空间
St1=(Seqstack *)malloc(sizeof(Seqstack ));//申请空间
(&Qu)->front=(linkqueuenode *)malloc(sizeof(linkqueuenode));//为头结点指针申请分配空间
Init(St);
Init(St1);
Initqueue(Qu);
printf ("\t********************************************************\n");
printf ("\t---------------Welcome to our Car Parking---------------\n");
printf ("\t* 1.车辆进入 *\n");
printf ("\t* 2.车辆离开 *\n");
printf ("\t* 3.显示停车场情况 *\n");
printf ("\t* 4.显示候车场情况 *\n");
printf ("\t* 5.离开 *\n");
printf ("\t--------------------------------------------------------\n");
do
{
scanf("%d",&com);
switch(com)
{
case 1: /*汽车到达*/
printf("输入车牌号和时间: ");
scanf("%d %d",&no,&time);
if (!StackFull(St)) /*停车场不满*/
{
Push(St,no,time);//进入停车场
printf(" >>停车场位置:%d\n",St->top+1);
}
else /*停车场满*/
{
if (!QueueFull(&Qu)) /*候车场不满*/
{
Enterqueue(&Qu,no);
printf(" >>候车场位置:%d\n",(&Qu)->rear);
}
else
printf(" >>候车场已满,不能停车\n");
}
break;
case 2: /*汽车离开*/
printf("输入车牌号和时间: ");
scanf("%d% d",&no,&time);
for (i=0; i<=St->top && St->carnum[i]!=no; i++); //在栈中找
if (i>St->top)
printf(" >>未找到该编号的汽车\n");
else
{
t = St->top - i; //需要出栈的车辆数目
for (j=0; j<t; j++) //不停的从停车场的栈中退出车辆,进入到临时栈St1
{
Pop(St,&e1,&e2);
Push(St1,e1,e2); //e1和e2都是从Pop()方法中得到的
}
Pop(St,&e1,&e2); //那个想要出去的汽车,离开
printf(" >>车牌号为%d的汽车停车费用为:%d\n",no,(time-e2)*Price);
while (!StackEmpty(St1)) /*将临时栈St1重新回到St中*/
{
Pop(St1,&e1,&e2);
Push(St,e1,e2);
}
if (!Isempty(&Qu)) /*队不空时,将队头进栈St*/
{
Deletequeue(&Qu,&e1);
Push(St,e1,time); /*以当前时间开始计费*/
}
}
break;
case 3: /*显示停车场情况*/
if (!StackEmpty(St))
{
printf(" >>停车场中的车辆:"); /*输出停车场中的车辆*/
Printstack(St);
}
else
printf(" >>停车场中无车辆\n");
break;
case 4: /*显示候车场情况*/
if (!Isempty(&Qu))
{
printf(" >>候车场中的车辆:"); /*输出候车场中的车辆*/
Printqueue(&Qu);
}
else
printf(" >>候车场中无车辆\n");
break;
case 0: /*结束*/
if (!StackEmpty(St))
{
printf(" >>停车场中的车辆:"); /*输出停车场中的车辆*/
Printstack(St);
}
if (!Isempty(&Qu))
{
printf(" >>候车场中的车辆:"); /*输出候车场中的车辆*/
Printqueue(&Qu);
}
break;
default: /*其他情况*/
printf(" >>输入的命令错误\n");
break;
}
}while(com!=0);
return 0;
}
3-4 测试与分析
3-4-1 测试数据的选择:
分别输入三组数据,作为进入到车辆,分别为(2 3)(4 5)(5 7);
输入一组数据作为离开的车辆为:(4 10);
查看停车场、候车场情况;
结束;
在测试一组数:直接case 2,输入离开车辆为(2 3)
在测试第三组数据:汽车(3 4)进入,汽车(3 4)离开
3-4-2 测试结果分析:
1.方法优缺点分析:
优点:用栈和队列来模拟停车场让整个问题显得简单,易于实现:
缺点:栈和队列这两个数学模型用在停车场管理上还是有失妥当的,现实中停车场出口入口不可能为同一处,不可能当辆车要离开,在它后面进来的车必须为它让路,因此无法用栈的“后进先出”原则来模拟:而且没有考虑便道上的车在等待过程中可以中途开走等情况,而这些都无法用队列的“先进先出”原则来模拟。
**
3-5 总结
**
此停车管理系统基本可能实现一个小的停车场的管理,其“到达”与“离开”方法都相对比较完整,以及结算清单明了。在时间方面我处理的比较简单,只是简单的整形变量表示。在输入数据时,要按照严格的格式输入,否则有可能出现死去或崩溃。若本系统能加上保存功能就更好了,因为一个系统在使用过程中总会关机等,而此系统的缺点却是没有保存功能,关闭之后就要重新建立了。以后会慢慢完善。