电梯模拟
一电梯模拟
一.题目要求
模拟某校九层教学楼的电梯系统。该楼有一个自动电梯,能在每层停留。九个楼层由下至上依次称为地下层、第一层、第二层、……第八层,其中第一层是大楼的进出层,即是电梯的“本垒层”,电梯“空闲”时,将来到该层候命。
乘客可随机地进出于任何层。对每个人来说,他有一个能容忍的最长等待时间,一旦等候电梯时间过长,他将放弃。
模拟时钟从0开始,时间单位为0.1秒。人和电梯的各种动作均要消耗一定的时间单位(简记为t),比如:有人进出时,电梯每隔40t测试一次,若无人进出,则关门;关门和开门各需要20t;每个人进出电梯均需要25t;如果电梯在某层静止时间超过300t,则驶回1层侯命。
要求:
按时序显示系统状态的变化过程,即发生的全部人和电梯的动作序列。
二.设计
1. 设计思想
(1)数据结构设计
构建一个栈用以表示乘客,用等待队列表示电梯外等待的乘客
(2)算法设计
1.乘客类型反映乘客的所有属性
2乘客栈类型,电梯内的乘客用乘客栈表示,去不同楼层的乘客放在不同的栈中。
3.等候队列类型,在电梯外等待的乘客用等待队列表示。每层各有两个等待队列,分别为上楼队列和下楼队列。
4.电梯类型,表示电梯的各个属性和所有动作。
2设计表示
1. 调用的函数如下:
#include
#include
#include
#include
#include
#include
#include
2. 各函数说明如下:
#define DownDecelerate 23 //下降减速
#define DoorTime 20 //开门关门时间
#define InOutTime 25 //进出电梯时间
#define Maxfloor 4 //最高层
#define Minfloor 0 //最低层
long Time=0; //时钟
long MaxTime;//系统运行最长时间
int InOutCount=0;//用于进出计时
int InterTime=0;//下一乘客进入系统的时间
int ID=0; //乘客编号
int GiveUpNumber=0;//乘客放弃的数目
int TotalTime=0;//总共等待时间
Status InitStack(ClientStack &S);//构造一个空栈
Status DestroyStack(ClientStack &S);//销毁栈S
Status ClearStack(ClientStack &S);//把S置为空
Status StackEmpty(ClientStack S);//若栈S为空,则返回TRUE,否则返回FALSE
int StackLength(ClientStack S);//返回栈S的长度
Status GetTop(ClientStack S,SElemType &e);//返回栈顶元素
Status Push(ClientStack &S,SElemType e);//入栈
Status Pop(ClientStack &S,SElemType &e);//出栈
void PrintStack(ClientStack &S);//输出栈
3. 详细设计
基本数据结构为:
Status EleAchieved(Elevator &E) {
//判断电梯是否要停于当前层
if(E.CallCar[E.floor]) return TRUE;
if(E.Stage==Up&&E.CallUp[E.floor]||E.Stage==Down&&E.CallDown[E.floor]) return TRUE;
if(E.Stage==Up&&E.CallDown[E.floor]&&!RequireAbove(E)) {
E.Stage=Down;return TRUE;
}
if(E.Stage==Down&&E.CallUp[E.floor]&&!RequireBelow(E)) {
E.Stage=Up;return TRUE;
}
return FALSE;
}
Status EleOpenDoor(Elevator &E) {
//判断电梯是否要开门
if(E.CallCar[E.floor]||E.CallDown[E.floor]&&E.Stage==Down||E.CallUp[E.floor]&&E.Stag e==Up)
return TRUE;
if(E.status==Waiting) {
if(E.CallDown[E.floor]) {E.Stage=Down;return TRUE;}
if(E.CallUp[E.floor]) {E.Stage=Up;return TRUE;}
}
return FALSE;
}
EleStage EleDecide(Elevator &E) {
//判断电梯动作
int Above,Below;
Above=RequireAbove(E);
Below=RequireBelow(E);
//无请求则停止
if(Above==0&&Below==0) return Stop;
//有请求则按请求移动
else {
if(E.Stage==Up) {
if(Above!=0) return Up;
else {
E.Stage=Down;return Down;
}
}//if
else {
if(Below!=0) return Down;
else {
E.Stage=Up;return Up;
}
}//if
}
}
Action ElevatorRun(Elevator &E){
//电梯状态转换
switch(E.status) {
case Opening:
//完成开门则转入Opened状态
E.status=Opened;E.Count=CloseTest;
return DoorOpened;
case Opened:
//进行关门测试
if(E.Stage==Down&&!E.CallCar[E.floor]&&!E.CallDown[E.floor]||
E.Stage==Up&&!E.CallCar[E.floor]&&!E.CallUp[E.floor]) {//无人进出,关门
E.status=Closing;E.Count=DoorTime;
}//if
break;
case Closing:
//完成关门则转入Closed状态
E.status=Closed;
return DoorClosed;
case Waiting:
//不在第一层且超出所规定的停候时间,电梯向第一层移动
if(E.Count==0) {
if(E.floor!=1) E.CallCar[1]=1;
}
else E.Count--;
//如果有人可以进入,则开门
if(EleOpenDoor(E)) {
E.status=Opening;E.Count=DoorTime;break;
}
case Closed:
//根据EleDecide的返回值设定电梯状态
switch(EleDecide(E)) {
case Up: E.status=Moving;E.Count=UpTime+Accelerate;return GoingUp;
case Down: E.status=Moving;E.Count=DownTime+Accelerate;return GoingDown;
case Stop:if(E.status!=Waiting) {E.status=Waiting;E.Count=OverTime;} };//switch
break;
case Moving:
//完成移动
if(E.Stage==Up) E.floor++;
else E.floor--;
if(EleAchieved(E)) {//到达目标层,转入减速状态
E.status=Decelerate;
E.Count=DownDecelerate;
}
else E.Count+=DownTime;//未到达目标层,继续下降
return Achieved;
case Decelerate:
//完成减速
//确定正确的电梯时期
if(E.Stage==Up&&!E.CallUp[E.floor]&&!RequireAbove(E)) E.Stage=Down;
else if(E.Stage==Down&&!E.CallDown[E.floor]&&!RequireBelow(E)) E.Stage=Up;
//转到开门状态
E.status=Opening;E.Count=DoorTime;
break;
};//switch
return None;
}//ElevatorRun
//单链队列——队列的链式存储结构
typedef Client *QElemType;
//等候队列
typedef struct QNode {
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct {
QueuePtr front; //队头指针
QueuePtr rear; //队尾指针
}WQueue;
//等待队列的基本操作
Status InitQueue(WQueue &Q) {
//构造一个空队列Q
Q.front=Q.rear=new QNode;
if(!Q.front) return OVERFLOW;//分配存储失败
Q.front->next=NULL;
Q.front->data=NULL;
return OK;
}
Status DestroyQueue(WQueue &Q) {
//销毁队列Q
while(Q.front) {
Q.rear=Q.front->next;
if(Q.front->data) DestoryClient(Q.front->data);
delete Q.front;
Q.front=Q.rear;
}
return OK;
}
Status EnQueue(WQueue &Q,QElemType e) {
//插入元素e为Q的新的队尾元素
QueuePtr p;
p=new QNode;
if(!p) return OVERFLOW;
p->data=e;p->next=NULL;
Q.rear->next=p;
Q.rear=p;
return OK;
}
Status DeQueue(WQueue &Q,QElemType &e) {
//若队列不空,则删除Q的队头元素,用e返回其值,并返回OK;
//否则返回ERROR
QueuePtr p;
if(Q.front==Q.rear) return ERROR;
p=Q.front->next;
e=p->data;
Q.front->next=p->next;
if(Q.rear==p) Q.rear=Q.front;
delete p;
return OK;
}
Status QueueEmpty(WQueue Q) {
//判断队列是否为空
if(Q.front==Q.rear) return TRUE;
else return FALSE;
}
Status QDelNode(WQueue &Q,QueuePtr p) {
//删除队列中p指向的结点的下一个结点
QueuePtr q;
if(p==NULL||p->next==NULL) return ERROR;
q=p->next;
p->next=q->next;
if(p->next==NULL) Q.rear=p;
DestoryClient(q->data);
delete q;
return OK;
}
Status CGiveUp(WQueue &Q,int floor) {
//删除放弃等待的乘客
QueuePtr p;
p=Q.front;
if(p->next!=NULL)
if(p->next->data->GivepuTime==0&&floor!=p->next->data->Infloor) {
PrintClientInfo(*(p->next->data),GiveUp);
TotalTime+=Time-CInTime(*(p->next->data));
QDelNode(Q,p);//将放弃等待的人删除
GiveUpNumber++;
}
else p->next->data->GivepuTime--;
return OK;
}
三.调试分析
这个题设计比较困难,其中大部分程序都是借鉴他人的,迄今为止,还有一些地方不大明白,,这个程序有很多变量,有的变量仅是在某些函数中赋予其值罢了,看来还需简洁。四.用户手册
在本设计中,用户只需按照提示依次输入正确的数值输入信息。程序运行后输入程序的运行时间,电梯开始运行。此间程序会一直运行到开始时输入的运行时间,此时整个程序运行结束,按任意键退出。
五.测试数据及测试结果
六.源程序清单
void InOut(Elevator &E,WQueue w[Maxfloor+1][2]) {
//进行乘客的进出电梯活动
//注意:电梯时期要正确,否则乘客无法进入。
Client *p;
if(E.CallCar[E.floor]) //人要从电梯中走出
if(StackEmpty(E.S[E.floor])) E.CallCar[E.floor]=0;
else {//当前层的乘客栈非空,出电梯
Pop(E.S[E.floor],p);E.ClientNumber--;
InOutCount=InOutTime;
PrintClientInfo(*p,Out);
TotalTime+=Time-CInTime(*p);
DestoryClient(p);
}//else
if(E.CallCar[E.floor]==0) //有人要走入电梯
if(!QueueEmpty(w[E.floor][E.Stage])) {//若队列不空,继续进电梯
DeQueue(w[E.floor][E.Stage],p);
Push(E.S[COutfloor(*p)],p);
if(E.CallCar[COutfloor(*p)]!=1) {
//按下要去楼层的按钮
E.CallCar[COutfloor(*p)]=1;
}
E.ClientNumber++;
InOutCount=InOutTime;
PrintClientInfo(*p,In);
}//if
else {//乘客的进出活动已完成
if(E.Stage==Down) E.CallDown[E.floor]=0;//将相应的下降按钮取消
else E.CallUp[E.floor]=0;//将相应的上升按钮取消
}
}
void NewClient(Elevator &E,WQueue w[5][2]) {
//进入新乘客
Client *p;
CreatClient(p);//新的乘客
//将该乘客插入相应队列并按下相应按钮(Up/Down)
if(GoAbove(*p)) {
EnQueue(w[CInfloor(*p)][Up],p);E.CallUp[CInfloor(*p)]=1;
}
else {
EnQueue(w[CInfloor(*p)][Down],p);E.CallDown[CInfloor(*p)]=1;
}//else
}
/**********************************************************/
void Print(Elevator &E,Action a) {
//输出电梯动作信息
switch(a) {
case DoorOpened:
cout<