1.需求分析
1.1输入的形式
输入的元素为整型类型;
输入的银行初始存款必须大于0;
输入的银行营业时间必须大于0且必须小于1440(一天);
输入的最大到达时间间隔必须大于0且必须小于银行营业时间;
输入的最小到达时间间隔必须大于0且必须小于最大到达时间间隔;
输入的最大处理时间必须大于0且必须小于银行营业时间;
输入的最小处理时间必须大于0且必须小于最大处理时间;
输入的交易额的最大上线必须大于0且必须小于银行初始存款且必须小于50000;
1.2输出的形式
输出的形式为以列表的形式输出事件处理序列;
并在列表输出完后输出需要存款的客户人数,需要取款的客户人数,成功办理存款的客户人数,成功办理取款的客户人数,存款成功办理率,取款成功办理率,客户逗留平均时间,银行当前余额等信息。
1.3程序功能
实现银行业务的事件驱动模拟系统,通过模拟方法求出客户在银行内逗留的平均时间。
1.4测试
测试数据由程序用户手动输入,此处对于正确输入和错误输入给出样例。
(1)错误的输入
(2)正确的输入
(3)对应的输出结果
2.概要设计
2.1数据类型
本设计中用到的数据结构ADT定义如下:
ADT Queue{
数据对象:D={ ai | ai∈ElemSet, i=1,2,...,n, n≥0 }
数据关系:R1={ <ai-1, ai>|ai-1, ai∈D, i=2,...,n }
基本操作:
void InitQueue(Queue &Q);
操作结果:构造空队列Q
CustNode *Queuefront(Queue &Q);
初始条件:队列Q存在
操作结果:返回队首元素
CustNode *Queuerear(Queue &Q);
初始条件:队列Q存在
操作结果:返回队尾元素
void EnQueue(Queue &Q,int e);
初始条件:队列Q存在
操作结果:插入元素e为Q的新的队尾元素。
void DeQueue(Queue &Q);
初始条件:队列Q存在
操作结果:删除Q的队头元素。
}ADT Queue
2.2主程序的流程
主程序先是让外部进行测试数据输入,待测试数据输入完后,执行银行业务模拟系统,产生需要取款的客户人数,成功办理存款的客户人数,成功办理取款的客户人数,存款成功办理率,取款成功办理率,客户逗留平均时间,银行当前余额等信息。
2.3程序模块说明
3.详细设计
3.1头文件声明
为了增强代码可读性,使用头文件来记录各类结构体的声明以及常用变量的定义
#ifndef _Bank_H_
#define _Bank_H_
#include <string>
using namespace std;
/*客户结点类型*/
struct CustNode{
int num; //客户号
string Type; //到达或离开
int BeginTime; //到达时间
int EndTime; //离开时间
int Amount; //正数为存款,负数为取款
CustNode *next; //指针域
};
Struct Client{
Int arrivertime; //到达时间
Int durtime; //逗留时间
Int amount; //办理业务金额
Client *next; //指针域
};
Client pool[MaxNumber];
/*等待队列类型*/
struct Queue{
CustNode *front; //队列头指针
CustNode *rear; //队列尾指针
}Queue;
/*常用变量定义*/
int BankAmount; //初始时银行现存资金总额
int CloseTime; //营业结束时间
int ClientArriveMaxTime; //两个到达事件之间的间隔上限
int ClientArriveMinTime; //两个到达事件之间的间隔下限
int DealMaxTime; //客户之间交易的时间上限
int DealMinTime; //客户之间交易的时间下限
int MaxAmount; //交易额上限
int NeedIn=0; //需要存款的人数
int NeedOut=0; //需要取款的人数
int SuccessIn=0; //成功存款的人数
int SuccessOut=0; //成功取款的人数
int CurrentTime=0; //当前时间
int BankAmountTime=0; //客户逗留总时间
int counter=0; //客户总数
int number=1; //初始客户序列号
bool state=1; //用于判断是否有窗口在处理
int DealTime=0; //交易时间
int MaxTime=0; //最大到达时间
Queue Event; //事件队列
Queue Q1; //队列一
Queue Q2; //队列二
#endif
3.2选做算法
3.2.1动态分配函数
/*出栈,将栈顶元素的下标返回*/
伪码表示:
Begin
Client *p<-栈顶指针
e的arrivetime<-栈顶元素的arrivertime
e的durtime<-栈顶元素的durtime
e的amount<-栈顶元素的amount
栈顶指针指向下一元素
End
代码表示:
void myMalloc(Stack &S,Client &e){
Client *p=S.top;
e.arrivetime=(*S.top).arrivetime;
e.durtime=(*S.top).durtime;
e.amount=(*S.top).amount;
p->next=p->next->next;
S.top++;
p=p->next;
}
3.2.2归还函数
/*把该分量入栈*/
伪码表示:
Begin
Client *p<-栈顶指针
栈底元素的arrivertimee<-e的arrivetime
栈底元素的durtime<-e的durtime
栈底元素的amount<-e的amount
栈底指针指向下一元素
End
代码表示:
void myFree(Stack &S,Client e){
Client *p=S.rear;
(*S.rear).arrivertime=e.arrivetime;
(*S.rear).durtime=e.durtime;
(*S.rear).amount=e.amount;
p->next=p->next->next;
S.rear++;
p=p->next;
}
3.3函数算法
3.3.1创建队列
/*初始化操作,建立一个空队列*/
伪码表示:
Begin
分配存储空间给头结点和尾结点
IF头结点内存分配失败
EXIT
头结点的指针域<-空
End
代码表示:
void InitQueue(Queue &Q){
Q.front=Q.rear=(CustNode*)malloc(sizeof(CustNode));
if(!(Q.front))
exit(1);
Q.front->next=0;
}
3.3.2入队列
/*插入元素e为队列Q的新的队尾元素*/
伪码表示:
Begin
分配存储空间给结点p
结点p的金额置<-e
结点p的指针域<-空
IF队列<-空
Begin
头指针<-p
尾指针<-p
End
ELSE
Begin
头指针next域<-p
尾指针<-尾指针next域
End
End
代码表示:
void EnQueue(Queue &Q,int e){
CustNode* p=new CustNode;
p->Amount=e;
p->next=NULL;
if(Q.front==NULL){
//队列为空,初始化
Q.front=p;
Q.rear=p;
}
else{
//队列不为空,插入结点p
Q.rear->next=p;
Q.rear=Q.rear->next;
}
}
3.3.3出队列
/*使p中的第一个元素出队列*/
伪码表示:
Begin
p<-头指针
IF p的next域<-空
Begin
头指针<-空
尾指针<-空
End
ELSE
头指针<-头指针的next域
DELETE p
End
代码表示:
void DeQueue(Queue &Q){
CustNode *p;
p=Q.front;
if(Q.front->next==NULL) //队列只有一个元素
Q.front=Q.rear=NULL;
else //调整队列头指针
Q.front=Q.front->next;
delete p;
}
3.3.4取队首
/*返回队首元素*/
伪码表示:
Begin
Return 队首元素
End
代码表示:
CustNode *Queuefront(Queue &Q){
return Q.front;
}
3.3.5取队尾
/*返回队尾元素*/
伪码表示:
Begin
Return 队尾元素
End
代码表示:
CustNode *Queuerear(Queue &Q){
return Q.rear;
}
3.3.6处理客户到达事件
/*随机产生顾客,进入队列一产生到达事件 进入事件队列*/
伪码表示:
Begin
调用EnQueue(Q1,随机数)
Q1尾结点的BeginTime<-CurrentTime
Q1尾结点的num<-number
EnQueue(Event,尾结点的金额)
Event尾结点的BeginTime<-CurrentTime
Event尾结点的Type<-到达
Event尾结点的num<-number
number<-number+1
End
代码表示:
void ClientArrive(){
EnQueue(Q1,(rand()%(2*MaxAmount)-MaxAmount)); //随机产生顾客加入第一队列
Queuerear(Q1)->BeginTime=CurrentTime; //当前时间为客户的到达时间
Queuerear(Q1)->num=number; //客户号为客户序列号
EnQueue(Event,(Queuerear(Q1)->Amount)); //将产生事件加入事件队列
Queuerear(Event)->BeginTime=CurrentTime;
Queuerear(Event)->Type="到达";
Queuerear(Event)->num=number;
number++;
}
3.3.7存款
/*对客户存款事件进行处理*/
伪码表示:
Begin
BankAmount<-BankAmount+Q1头结点的Amount
调用EnQueue(Event,Q1头结点的Amount)
Event尾结点的Type<-离开
Event尾结点的num<-Q1头结点的num
Event尾结点的EndTime<-Q1头结点的BeginTime+随机处理时间
counter<-counter+1
BankAmountTime<-BankAmountTime+Event尾结点的EndTime-Q1头结点的BeginTime
调用DeQueue(Q1)
DealTime<-Event尾结点的EndTime
state<-0
End
代码表示:
void InAmount(){
BankAmount+=Queuefront