一、实验目的
通过停车场管理的程序设计,帮助学生熟练掌握栈和队列的基本操作及用栈与队列解决具体问题的基本方法。
二、实验内容
设停车场是一个可以停放n辆汽车的狭长通道,且只有一个大门可供汽车进出。
汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端,最先到达的第一辆车停放在车场的最北端);
若车场内已停满n辆汽车,则后来的汽车只能在门外的便道上等候,一旦有车开走,则排在便道上的第一辆车即可进入;
当停车场某辆车要离开时,在它之后进入的车辆必须先退出车场为它让路,待该辆车开出大门外,其它车辆再按原次序进入车场;
汽车可以直接从便道上离开。离开时排在前面的车也应该为其让道,随后应回到原来的位置。
每辆停放在车场的车在它离开停车场时必须按它停留的时间长短交纳费用。交费按车的类型不同而不同,假定小车每小时2元,客车每小时3元,卡车每小时5元。停在便道上的车也要交费,假设其费用为停车场的车的1/3。
停车只限于当天0点至24点。
编写程序实现上面要求的停车场停车管理功能。
三、实验原理
1、停车场的数据逻辑表示
停车场包括正式的停车场和停车场外的暂停便道。按照要求,汽车在停车场内按车辆到达时间的先后顺序,依次由北向南排列(大门在最南端),离开时只能从大门口离开。因此以栈模拟停车场比较合适。对栈的操作,汽车进入停车场是严格按入栈操作进行。汽车离开停车场时不一定是最接近大门的车辆,可以是停车场中的任何一辆车,所以汽车离开操作不是严格的出栈操作。但汽车离开停车场后的数据仍然按栈的方式进行组织。
由于暂停便道的车辆当停车场有空位时要进入停车场,而进入停车场的顺序是按进入便道的先后顺序进行的。因此用队列模拟停车场外的暂停便道比较恰当。
假设停车场最多可停放6辆车,初始为空,有连续9两车进入车场,则其中6辆车停在停车场,另有3辆车停在便道上,如图3-1所示。
按照从终端读入的输入数据进入模拟管理。每一组输入数据包括三个数据项:
汽车“到达”或“离去”信息
汽车牌照号码
汽车到达或离去的时刻(以小时为单位记数)
对每一组输入数据进行操作后的输出信息为:
若是车辆“到达”,则输出汽车在停车场内或便道上的停车位置。
若是车辆“离去”,则输出汽车在车场内停留的时间和应交纳的费用。
2、汽车从停车场离开的处理
当汽车从停车场离开时,若该车就是最靠近大门的车(在栈中处于栈顶位置),则直接开出停车场。若不是最靠近大门的车(不在栈顶),则处在靠近大门的车(栈顶位置)要让道。当要离开的车离开停车场后,让道的车又要按原来的顺序进入停车场。按照让道离开顺序和重新进入停车场的顺序,符合栈操作的规律,所以需要设置一个辅助栈来保存让道的车辆信息。
对于上面车辆离开停车场的两种情况,若暂停便道上有车,则便道上排在最前面的车要进入停车场。
假设4号车要离开车场,则应按6号车、5号车的顺序依次进入让路便道。当4号车开走后,应按5号车、6号车的顺序依次进入停车场。这时停车场空出一个位置,然后7号车进入停车场。图3-2表示4号车正在离开时的情况。
3、车辆从暂停便道离开的表示
假设车辆只能向前开,而不是后退的形式离开便道。当汽车从便道离开时,若该车排在最前面,则可直接离开。若不是排在最前面,则处在前面的车要让道。让道的方式有两种方案:
(1)前面的车直接开到后面去排队。如果司机都希望把汽车开到停车场停靠,显然这种处理方式式不公正的。
(2)让道的车让道后回到原来排队位置(这是比较公正的处理方法)。但要实现这种处理方式必须另开辟场所停放让道车辆,在处理相关数据时,必须另设一辅助数据结构来存放前面让道的车辆的信息,该辅助数据结构应该是栈。
4、辅助功能
(1)菜单选择:将上述基本功能通过“菜单”形式罗列出来,通过菜单选择进行交互式控制程序运行。
(2)队列初始化InitQueue
(3)静态栈进栈操作Push
(4)静态栈出栈操作Pop
(5)判栈空满操作StackEmpty
(6)判栈满操作StackFull
(7)队列进队操作EnQue
(8)队列出队操作DeQue
(9)判队列空操作QueueEmpty
(10)撤销队列操作DestroyQue
(11)链式栈进栈操作(从暂停便道让道的车辆信息用链式栈保存)LPush
(12)链式栈出栈操作LPop
(13)栈信息查找SearchStack:车辆进入车场的信息录入后,通过查找判断停车场栈中是否有重复信息录入;当离开车辆的信息录入后,通过查找确定要离开车辆在停车场栈中的位置。
(14)队列信息查找SearchQueue::车辆进入车场的信息录入后,通过查找判断停车场栈中是否有重复信息录入;当离开车辆的信息录入后,通过查找确定要离开车辆在停车场栈中的位置。
(15)计算停车缴费CalcultPay
(16)输出车场车辆信息OutputBusData
5、
主要算法描述
算法1】车辆到达数据录入算法功能:
(1)录入一组有效的车辆到达数据。数据有效指车辆编号大于0,到达时间大于0,车辆类型编码满编码约定要求。
(2)判断车辆是否满足唯一性要求。车辆编号是车辆的唯一性标志,唯一性要求指新到达的车辆在停车场和暂停便道上都未出现。
(3)若停车场还可以停车(停车场栈不满),则把车辆数据插入到停车场栈中,否则插入到暂停便道队列中。
【算法2】车辆离开数据录入算法功能:
(1)录入一组有效的车辆离开数据。数据有效指车辆编号大于0,离开时间大于0。
(2)若要离开的车辆在停车场栈中,则:
① 将栈中要离开的车辆的栈顶前面的车辆数据移到让车便道栈中,
② 计算离开车辆应缴停车费并显示。
③ 让车便道栈的数据移到停车场栈。
④ 如果暂停便道队列有数据,则将对头数据移到停车场栈。
(3)若要离开的车辆数据在暂停便道队列中,则:
① 将队列中要离开的车辆的队头前面的车辆数据移到链式栈中。
② 计算离开车辆应缴停车费并显示。
③ 将链式栈中数据移到暂停便道队列头部。
算法描述如图3-7所示。
本人遇到的问题
因为之前用的栈和队列都是在JAVA中实现,在C中就要考虑指针的问题。
开始的时候太过按部就班:
书上的顺序栈
typedf struct{
SElemType *base;
SElemType top;
int stacksize;
}stack;
这里用到的栈
struct SqStack{
BUSINF elm[STACKSIZE];
int top;
}stack;
书上的链队列
typedef struct QNODE{
BUSINF elm;
struct QNODE *next;
}QNODE,*QueuePtr;
struct LinkQueue{
QueuePtr front;
QueuePtrE rear;
}Queue;
这里的定义
typedef struct QNODE{
BUSINF elm;
struct QNODE *next;
}QNODE;
struct LinkQueue{
QNODE *front;
QNODE *rear;
}Queue;
这些关于指针的细微差别,让我在调用一些函数时无从下手,不敢写。
在重新审视了一遍书中关于指针和结构体的概念后才好一些。
其实作为一道实验作业,算法中的大部分是现成的。而在学生完成的这部分中,最麻烦的两个函数方法“车辆出入管理”都是由学生完成,也是最考验功力的地方,但其实已经提供了需要定义的变量,相信大部分初学者都可以自行推理出具体实现。废话不多说,附上代码:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>
#define STACKSIZE 5
int OVERFLOW=0;
/*-----------车辆数据结构定义-------------*/
typedef struct{
int BNo; //车辆编号
int type; //车辆类型
int arrivetime; //到达车场时间
int pushtime; //进入停车场时间
int departuretime; //离开车场时间
}BUSINF;
/*------------顺序栈结构定义----------------*/
struct SqStack{
BUSINF elm[STACKSIZE];
int top;
}stack;
/*------------链队列结点结构定义-----------*/
typedef struct QNODE{
BUSINF elm;
struct QNODE *next;
}QNODE;
/*-------------链队列结构定义---------------*/
struct LinkQueue{
QNODE *front;
QNODE *rear;
}Queue;
/*-----------车辆收费标准定义----------------*/
int pay[]={0,2,3,5};
/*-------------------------------------------*/
/* 判栈空函数 */
/* 参 数:struct SqStack stack--指定栈 */
/* 返回值:0--栈不空; 1--栈空 */
/*-------------------------------------------*/
int StackEmpty(struct SqStack stack)
{
if(stack.top==0) return 1;
else return 0;
//(学生完成)
}
/*-------------------------------------------*/
/* 判栈满函数 */
/* 参 数:struct SqStack stack--指定栈 */
/* 返回值:0--栈不满; 1--栈满 */
/*-------------------------------------------*/
int StackFull()
{
if(stack.top==STACKSIZE) return 1;
else return 0;
//(学生完成)
}
/*-------------------------------------------*/
/* 顺序栈入栈函数 */
/* 参 数:struct SqStack *stack--栈指针 */
/* BUSINF Bus--入栈车辆数据 */
/* 返回值:无 */
/*-------------------------------------------*/
void push(struct SqStack *stack,BUSINF Bus)
{
stack->elm[stack->top++]=Bus;
//(学生完成)
}
/*-------------------------------------------*/
/* 顺序栈出栈函数 */
/* 参 数:struct SqStack *stack--栈指针 */
/* BUSINF *Bus--返回车辆数据指针 */
/* 返回值:无 */
/*-------------------------------------------*/
void pop(struct SqStack *stack,BUSINF *Bus)
{
if(StackEmpty(*stack))
return;
else
{
*Bus=stack->elm[--stack->top];
}
//(学生完成)
}
/*-------------------------------------------*/
/* 链栈入栈函数 */
/* 参 数:QNODE *stack--栈指针 */
/* QNODE *p--入栈结点指针 */
/* 返回值:无 */
/*-------------------------------------------*/
void LPush(QNODE *stack,QNODE *p)
{ p->next=stack->next;
stack->next=p;
}
/*-------------------------------------------*/
/* 链栈出栈函数 */
/* 参 数:QNODE *stack--栈指针 */
/* QNODE **p--返回结点指针 */
/* 返回值:无 */
/*-------------------------------------------*/
void LPop(QNODE *stack,QNODE **p)
{ (*p)=stack->next;
stack->next=(*p)->next;
}
/*-------------------------------------------*/
/* 链队列初始化函数 */
/* 参数:无 */
/* 返回值:无 */
/*-------------------------------------------*/
void InitQueue(void)
{
Queue.front=Queue.rear=(QNODE *)malloc(sizeof(QNODE));
if(!Queue.front) exit(OVERFLOW);
Queue.front->next=NULL;
//(学生完成)
}
/*-------------------------------------------*/
/* 判队列空函数 */
/* 参 数:无 */
/* 返回值:0--队列不空; 1--队列空 */
/*-------------------------------------------*/
int QueueEmpty(void)
{
if(Queue.front==Queue.rear) return 1;
else return 0;
//(学生完成)
}
/*-------------------------------------------*/
/* 入队操作函数 */
/* 参 数:BUSINF Businf--入队车辆数据 */
/* 返回值:无 */
/*-------------------------------------------*/
void EnQueue(BUSINF Businf)
{ QNODE *p;
p=(QNODE *)malloc(sizeof(QNODE));
if(!p) exit(OVERFLOW);
p->elm=Businf;
p->next=NULL;
Queue.rear->next=p;
Queue.rear=p;
// (学生完成)
}
/*-------------------------------------------*/
/* 出队操作函数 */
/* 参 数:BUSINF *Businf--返回车辆数据指针 */
/* 返回值:无 */
/*-------------------------------------------*/
void DeQueue(BUSINF *BusInf)
{ QNODE *p;
if(QueueEmpty()) return;
p=Queue.front->next;
*BusInf=p->elm;
Queue.front->next=p->next;
if(Queue.rear==p) Queue.rear=Queue.front;
free(p);
//(学生完成)
}
/*-------------------------------------------*/
/* 栈数据查找函数 */
/* 参 数:int BusNo--待查找的车辆编号 */
/* 返回值:int:>=0--数据在栈中的位置 */
/* -1--查找失败 */
/*-------------------------------------------*/
int SearchStack(int BusNo)
{ int k;
k=stack.top-1;
while(k>=0&&BusNo!=stack.elm[k].BNo) k--;
return(k);
}
/*-------------------------------------------*/
/* 队列数据查找函数 */
/* 参 数:int BusNo--待查找的车辆编号 */
/* 返回值:队列结点指针:NULL--查找失败 */
/* 非空--查找成功,数据结点指针 */
/*-------------------------------------------*/
QNODE *SearchQueue(int BusNo)
{ QNODE *p;
p=Queue.front->next;
while(p!=NULL&&p->elm.BNo!=BusNo) p=p->next;
return(p);
}
/*-------------------------------------------*/
/* 收费计算与显示函数 */
/* 参 数:BUSINF BusInf--离开车辆的数据 */
/* 返回值:无 */
/*-------------------------------------------*/
void CalcultPay(BUSINF BusInf)
{ int payment;
if(BusInf.arrivetime!=0&&BusInf.pushtime==0)
payment=(BusInf.departuretime-BusInf.arrivetime)*pay[BusInf.type]/3.0;
else if(BusInf.arrivetime!=0&&BusInf.pushtime!=0)
payment=(BusInf.pushtime-BusInf.arrivetime)*pay[BusInf.type]/3.0+
(BusInf.departuretime-BusInf.pushtime)*pay[BusInf.type];
else payment=(BusInf.departuretime-BusInf.pushtime)*pay[BusInf.type];
printf(" \n ************************\n");
printf(" * payment=%4d *\n",payment);
printf(" ************************\n");
getch();
}
/*-------------------------------------------*/
/* 进场车辆数据录入与管理函数 */
/* 参 数:无 */
/* 返回值:无 */
/*-------------------------------------------*/
void InputArrialData()
{ int BusNo,arrivetime,BusType;
BUSINF arrive;
int i=0;
do
{
do
{
printf("Input BusNo:");
scanf("%d",&BusNo);
if((SearchStack(BusNo)!=-1)||(SearchQueue(BusNo)!=NULL))
{
printf("The Bus is in BusData:\n");
}
else i=1;
}while(!i);
arrive.BNo=BusNo;
printf("Input arrivetime:");
scanf("%d",&arrivetime);
arrive.arrivetime=arrivetime;
printf("1.Car 2.Bus 3.Truck ");
printf("\nInput Type:");
scanf("%d",&BusType);
arrive.type=BusType;
}while(!(BusNo>0&&arrivetime>0&&0<BusType<=3));
if(StackFull())
{
arrive.pushtime=-1;
EnQueue(arrive);
}
else
{
arrive.pushtime=arrive.arrivetime;
push(&stack,arrive);
}
}//(学生完成)
/*-------------------------------------------*/
/* 离场车辆数据录入与管理函数 */
/* 参 数:无 */
/* 返回值:无 */
/*-------------------------------------------*/
void InputDepartData()
{ int BusNo,departtime;
int f=0,bn;
BUSINF depart,temp;
QNODE *p,*pri,*q;
QNODE *LStack;
struct SqStack TempStack;
if(StackEmpty(stack)&&QueueEmpty())
{
printf("Iput error!");
getch();
return;
}
printf("Input the BusNo:");
do
{
scanf("%d",&BusNo);
}while(BusNo<0);
if(SearchStack(BusNo)==-1&&SearchQueue(BusNo)==NULL)
printf("\nThe BusNo is not in Data!");
else
{
if(SearchStack(BusNo)!=-1) //说明在停车场上
{
f=1;
bn=SearchStack(BusNo);
printf("Input deparetime:");
do
{
scanf("%d",&stack.elm[bn].departuretime);
}while(stack.elm[bn].departuretime<stack.elm[bn].pushtime);
if(QueueEmpty()) //说明链队列为空
{
if(stack.top==bn+1) //在栈顶
{
pop(&stack,&depart);
}
else //不在栈顶
{
int flg=0;
while(stack.top>bn+1)
{
pop(&stack,&depart);
TempStack.elm[flg++]=depart;
}
pop(&stack,&depart);
do
{
push(&stack,TempStack.elm[flg-1]);
flg--;
}while(flg);
}
}
else //说明链队列不为空
{
if(stack.top==bn+1) //在栈顶
{
pop(&stack,&depart);
DeQueue(&temp);
temp.pushtime=depart.departuretime;
push(&stack,temp);
}
else //不在栈顶
{
int flg=0;
while(stack.top>bn+1)
{
pop(&stack,&depart);
TempStack.elm[flg++]=depart;
}
pop(&stack,&depart);
do
{
push(&stack,TempStack.elm[flg-1]);
flg--;
}while(flg);
DeQueue(&temp);
temp.pushtime=depart.departuretime;
push(&stack,temp);
}
}
}
else //说明在暂停车道上
{
p=SearchQueue(BusNo);
printf("Input departuretime:");
do
{
scanf("%d",&p->elm.departuretime);
}while(p->elm.departuretime<p->elm.arrivetime);
if(p==Queue.front->next) //在队列头部
DeQueue(&depart);
else //不在队列头部
{
while(p!=Queue.front->next)
{
DeQueue(&depart);
q=(QNODE *)malloc(sizeof(QNODE));
q->elm=depart;
LPush(LStack,q);
}
DeQueue(&depart);
while(LStack->next)
{
LPop(LStack,&pri);
if(QueueEmpty())
{
pri->next=Queue.front->next;
Queue.front->next=pri;
Queue.rear=Queue.front;
}
else
{
pri->next=Queue.front->next;
Queue.front->next=pri;
}
}
}
}
printf("\nThe car:\n");
if(f)
{
printf(" CarNo Arrivetime Pushtime departuretime\n");
printf(" %-13d%-18d%-16d%-d",depart.BNo,depart.arrivetime,depart.pushtime,depart.departuretime);
}
else
{
printf(" CarNo Arrivetime departuretime\n");
printf(" %-13d%-18d%-d",depart.BNo,depart.arrivetime,depart.departuretime);
}
CalcultPay(depart);
}
}//(学生完成)
/*-------------------------------------------*/
/* 列表显示车场车辆数据函数 */
/* 参 数:无 */
/* 返回值:无 */
/*-------------------------------------------*/
void OutputBusData(void)
{ int i;
QNODE *p;
printf("\n stop:\n");
printf(" CarNo Arrivetime Pushtime\n");
getch();
for(i=0;i<stack.top;i++)
printf("%8d%8d%10d\n",stack.elm[i].BNo,stack.elm[i].arrivetime,
stack.elm[i].pushtime);
if(Queue.front->next)
{ printf("\n path:\n");
p=Queue.front->next;
while(p)
{ printf(" %d %d\n",p->elm.BNo,p->elm.arrivetime);
p=p->next;
}
}
}
/*-------------------------------------------*/
/* 撤销队列函数 */
/* 参 数:无 */
/* 返回值:无 */
/*-------------------------------------------*/
void DestroyQue()
{ QNODE *p,*q;
p=Queue.front;
while(p)
{ q=p;
p=p->next;
free(q);
}
}
/*-------------------------------------------*/
/* 菜单选择函数 */
/* 参 数:无 */
/* 返回值:int:取值1--3 */
/*-------------------------------------------*/
int nemu()
{
char m;
printf("\n ************* BUS Manage **************\n");
printf(" *%15c1---Arrival%12c\n",' ','*');
printf(" *%15c2---Departure%10c\n",' ','*');
printf(" *%15c3---End%16c\n",' ','*');
printf(" ***************************************\n");
printf("%15cSelcet 1,2,3: ",' ');
do{
m=getch();
}while(m<'1' || m>'3');
printf("\n");
return(m-48);
}
void main()
{ stack.top=0;
InitQueue();
while(1)
{
switch(nemu())
{
case 1:
InputArrialData();
OutputBusData();
break;
case 2:
InputDepartData();
OutputBusData();
break;
case 3:
OutputBusData();
DestroyQue();
return;
}
}
}