一道闹心的数据结构作业,请读者仔细读题,理清思路,这个问题的逻辑有点绕。
/****************************************************
文件名:事件驱动模拟
创建人:张劲暾(OrdinaryCrazy)
描述:银行用户模拟程序
创建时间:20171015
*****************************************************/
#include <iostream>
#include <cstdlib>
#include <cstdio>
#define OK 1
#define ERROR 0
#define Ture 1
#define False 0
#define OVERFLOW -1
using namespace std;
typedef int Status;
FILE* f;
int total;//初始总金额
int Lasttotal;//第一个队列中最后一个第二类客户被接待之前的余额
int closetime;//关门时间
int arrivedur[2],solvedur[2];//到达间隔时间和交易时间的上下界
int numbersize[2];//交易金额的上下界
int totaltime,cusnum;
int Random_for_number(){//专门用于产生交易金额的随机值的函数
int a = rand(),b = rand();
if(b%2) a = (-1) * (a%numbersize[0]) - 1;
else a = (a%numbersize[1]) + 1;
return a;
}//Random_for_number
int Random(int top,int floor){//随机产生top与floor之间的随机数
if(floor > top){cout<<"请停止你愚蠢的行为。"<<endl;exit(0);}
int a = (rand()%top) + 1;
while(a < floor) a = (rand()%top) + 1;
return a;
}//Random
typedef struct{//事件类型:Event
int type;//事件类型,0--用户来到,1--用户在1号窗口办理业务,2--用户在2号窗口办理业务,3--用户在1号窗口离开,4--用户在2号窗口离开
int occurtime;//事件发生的时间
}Event;
typedef struct ENL{//事件链表类型:EventL,*EventList
Event event;
struct ENL* next;
}EventL,*EventList;
typedef struct{//客户类型:customer;
int arrivetime;//客户到达时间
int durtime;//交易时间
int number;//客户序号
int amount;//客户交易金额
}customer;
typedef struct QNL{//窗口事件类型:Queue;
customer cus;
struct QNL* next;
}Queue;
typedef struct{//窗口队列:*win,window;
Queue* head;
Queue* rear;
}window,*win;
Event option; //当前处理时间
window win1,win2; //两个窗口
EventList ev; //事件列表(有头结点单向链表)
int num2; //这个变量记录了当一个2号窗口离开事件发生时,该窗口还有多少人没有被接待
int QueueLength(window Q){ //返回队列长度
int len = 0;
Queue* tmp = Q.head;
while(tmp != Q.rear){len++;tmp = tmp->next;}
return len;
}//QueueLength
Status DelList(EventList &L,Event &E){ //删除列表第一个元素并用E返回
EventList tmp = L->next;
if(!tmp) return ERROR; //空表
E = tmp->event;
L->next = tmp->next;
free(tmp);
return OK;
}//DelList
Status EnQueue(window &W,customer C){ //将客户插入到对应队列中
Queue* tmp = (Queue*)malloc(sizeof(Queue));
tmp->cus = C;
tmp->next = NULL;
W.rear->next = tmp;
W.rear = tmp;
return OK;
}//EnQueue
Status InitList(EventList &L){ //链表初始化操作
L = (EventList)malloc(sizeof(EventL)); //链表头结点
L->event.occurtime = L->event.type = -1;
L->next = NULL;
return OK;
}//InitList
Status OrderInsert(EventList &L,Event E){ //将事件E按照时间先后顺序插入到事件链表中
EventList ins = (EventList)malloc(sizeof(EventL));
ins->event = E; //先产生我们要插入的结点
if(L->next == NULL){L->next = ins; ins->next = NULL;} //空表
else {
EventList tmp = L;
while(tmp->next && E.occurtime > tmp->next->event.occurtime) tmp = tmp->next;
if(tmp->next == NULL){tmp->next = ins;ins->next = NULL;} //发生的最晚的情况
else{
ins->next = tmp->next;
tmp->next = ins;
}//else
}//else
return OK;
}//OrderInsert
Status InitWin(window &W){ //队列初始化操作
W.head = (Queue*)malloc(sizeof(Queue));
if(!W.head) exit(OVERFLOW);
W.rear = W.head;
W.head->next = NULL;
return OK;
}//InitWin
Status DelQueue(window &W,customer &C){ //出队(办理业务)
Queue* first = W.head->next;
if(!first) return ERROR;
C = first->cus;
W.head->next = first->next;
if(first == W.rear) W.rear = W.head; //删除的是尾节点
free(first);
return OK;
}//DelQueue
Status Get_head_Win(window &W,customer &C){ //查看窗口前第一位客户的情况
C = W.head->next->cus;
return OK;
}//Get_head_Win
Status From_1_to_2(){ //将1号窗口的第一个人转移到2号窗口
customer tmp;
DelQueue(win1,tmp);
EnQueue(win2,tmp);
if(QueueLength(win1) > 0){
Event tmpE;
tmpE.occurtime = option.occurtime;
tmpE.type = 1;
OrderInsert(ev,tmpE);
}
return OK;
}//From_1_to_2
Status ClearQueue(window &W){ //驱逐客户并统计了他们逗留的时间
while(QueueLength(W) > 0){
customer tmp;
DelQueue(W,tmp);
fprintf(f,"很遗憾没能为 %d 号顾客提供服务\n",tmp.number);
cout<<"很遗憾没能为 "<<tmp.number<<" 号顾客提供服务"<<endl;
totaltime += (closetime - tmp.arrivetime);
}//while
return OK;
}//ClearQueue
Status Open_for_Day(){ //初始化操作
totaltime = cusnum = num2 = 0;
InitList(ev);
InitWin(win1);
InitWin(win2);
option.occurtime = option.type = 0; //我们假设一开门就有一个用户进入
OrderInsert(ev,option);
return OK;
}//Open_for_Day
Status End_for_Day(){ //一天结束,释放动态分配的内存
free(ev);
free(win1.head);
free(win2.head);
return OK;
}//End_for_Day
Status Customer_arrive(){ //客户到达处理函数
cusnum++;
int durtime = Random(solvedur[1],solvedur[0]);
int intertime = Random(arrivedur[1],arrivedur[0]);
if(option.occurtime + intertime < closetime){ //如果下一个人还来得及
Event tmp;
tmp.occurtime = option.occurtime + intertime;
tmp.type = 0;
OrderInsert(ev,tmp);
}//if
customer custmp;
custmp.number = cusnum;
custmp.arrivetime = option.occurtime;
custmp.amount = Random_for_number();
custmp.durtime = durtime; //创建客户
EnQueue(win1,custmp); //默认他到一号窗口排队
if(QueueLength(win1) == 1 && num2 == 0){
Event tmp;
tmp.type = 1;
tmp.occurtime = custmp.arrivetime;
OrderInsert(ev,tmp);
}//if
fprintf(f,"第 %d 号顾客于第 %d 分钟进入银行\n",custmp.number,custmp.arrivetime);
cout<<"第 "<<custmp.number<<" 号顾客于第 "<<custmp.arrivetime<<" 分钟进入银行"<<endl;
return OK;
}//Customer_arrive
Status ClearList(EventList &L){ //清空事件链表
Event tmp;
while(ev->next){
DelList(ev,tmp);
if(tmp.type == 0) Customer_arrive();
}
return OK;
}//ClearList
void Check_2(){ //检查2号窗口
if(num2){ //如果二号窗口还有没接待过的顾客,那么继续在2号窗口服务
Event tmpE;
tmpE.occurtime = option.occurtime;
tmpE.type = 2;
OrderInsert(ev,tmpE);
}
else if(QueueLength(win1)){
Event tmpE;
tmpE.occurtime = option.occurtime;
tmpE.type = 1;
OrderInsert(ev,tmpE);
}
}//Check_2()
Status Customer_solve1(){ //客户在1号窗口办理业务
customer tmp;
Lasttotal = total; //以防万一
Get_head_Win(win1,tmp); //我们来接待1号队列的第一位客户
fprintf(f,"第 %d 号顾客于第 %d 分钟在1号窗口办理业务。\n",tmp.number,option.occurtime);
fprintf(f,"此时总金额:%d。\t",total);
fprintf(f,"该用户的交易金额:%d。\n",tmp.amount);
cout<<"第 "<<tmp.number<<" 号顾客于第 "<<option.occurtime<<" 分钟在1号窗口办理业务。"<<endl;
if(tmp.amount + total < 0){ //如果这位客户是来取钱的然而银行并没有那么多的小钱钱
fprintf(f,"第 %d 号顾客转移到2号队伍\n",tmp.number);
cout<<"第 "<<tmp.number<<" 号顾客转移到2号队伍。"<<endl;
From_1_to_2();
}//if
else{
int leavetime = option.occurtime + tmp.durtime; //你都开始办理业务了,什么时候走我们不是之前说好的吗?
if(leavetime > closetime) {
ClearList(ev);
ClearQueue(win1);ClearQueue(win2);
}//不好意思我们下班了
else{
Event tmpE;
tmpE.occurtime = leavetime;
tmpE.type = 3;
OrderInsert(ev,tmpE); //产生一个1号窗口离开事件并插入到事件列表中
}//else
}//else
return OK;
}//Customer_solve1
Status Customer_solve2(){ //客户在2号窗口办理业务
customer tmp;
Get_head_Win(win2,tmp);//让我们从头开始接待等待在二号窗口前的顾客
fprintf(f,"第 %d 号客户在2号窗口办理业务\n",tmp.number);
fprintf(f,"此时总金额:%d。\t",total);
fprintf(f,"一号窗口余额:%d。\t",Lasttotal);
fprintf(f,"该用户的交易金额:%d。\n",tmp.amount);
cout<<"第 "<<tmp.number<<" 号客户在2号窗口办理业务"<<endl;
num2--;
if(tmp.amount + total < Lasttotal){ //让这个该死的抢劫犯到后面去
fprintf(f,"第 %d 号客户未能在2号窗口办理业务\n",tmp.number);
cout<<"第 "<<tmp.number<<" 号客户未能在2号窗口办理业务"<<endl;
DelQueue(win2,tmp);
EnQueue(win2,tmp);
Check_2();
}//if
else{ //那我们可以接待你了
if(option.occurtime + tmp.durtime > closetime){
ClearList(ev);
ClearQueue(win1);ClearQueue(win2);
}//不好意思我们下班了
else{
Event newE;
newE.occurtime = option.occurtime + tmp.durtime;
newE.type = 4;
OrderInsert(ev,newE);
}//else
}//else
return OK;
}//Customer_solve2
Status Customer_leave1(){ //客从1号窗口户离开
customer tmp;
DelQueue(win1,tmp);
total += tmp.amount;
totaltime += option.occurtime - tmp.arrivetime;
if(tmp.amount > 0 && QueueLength(win2)){ //如果这个人是存了钱,而且此时2号窗口有人在等待,那么就产生了一个在二号窗口办理业务的事件
Event newE;
newE.type = 2;
newE.occurtime = option.occurtime;
OrderInsert(ev,newE);
num2 = QueueLength(win2); //这是现在二号窗口尚未处理的人数;
}//if
else if(QueueLength(win1)){
Event newE;
newE.type = 1;
newE.occurtime = option.occurtime;
OrderInsert(ev,newE);
}
fprintf(f,"第 %d 号顾客于第 %d 分钟从1号窗口离开银行。\t",tmp.number,option.occurtime); //这里不换行,便于查看
fprintf(f,"此时总等待时间:%d。\t",totaltime);
fprintf(f,"该用户等待时间:%d。\t",option.occurtime - tmp.arrivetime);
cout<<"第 "<<tmp.number<<" 号顾客于第 "<<option.occurtime<<" 分钟从1号窗口离开银行"<<endl;
return OK;
}//Customer_leave1
Status Customer_leave2(){ //客户从2号窗口离开
customer tmp;
DelQueue(win2,tmp);
total += tmp.amount;
totaltime += option.occurtime - tmp.arrivetime;
fprintf(f,"第 %d 号顾客于第 %d 分钟从2号窗口离开银行。\t",tmp.number,option.occurtime); //这里不换行,便于查看
fprintf(f,"此时总等待时间:%d。\t",totaltime);
fprintf(f,"该用户等待时间:%d。\t",option.occurtime - tmp.arrivetime);
cout<<"第 "<<tmp.number<<" 号顾客于第 "<<option.occurtime<<" 分钟从2号窗口离开银行"<<endl;
Check_2();
return OK;
}//Customer_leave2
Status Banksim(){ //银行业务模拟程序
Open_for_Day(); //一天的初始化
while(ev->next){
DelList(ev,option); //发生了一件事
if(option.type == 1) Customer_solve1();
else if(option.type == 2) Customer_solve2();
else if(option.type == 3) Customer_leave1();
else if(option.type == 4) Customer_leave2();
else Customer_arrive();
}//while
End_for_Day();
return OK;
}//Banksim()
int main(){
srand((int)time(NULL));
cout<<"请输入相关变量:"<<endl;
cout<<"请输入初始时银行现存总金额:"<<endl;
cin>>total;
cout<<"请输入营业时间:"<<endl;
cin>>closetime;
cout<<"请输入到达间隔时间的下界和上界:"<<endl;
cin>>arrivedur[0]>>arrivedur[1];
if(arrivedur[0] > arrivedur[1]){cout<<"请停止你愚蠢的行为。"<<endl;exit(0);};
cout<<"请输入交易时间的下界和上界:"<<endl;
cin>>solvedur[0]>>solvedur[1];
if(solvedur[0] > solvedur[1]){cout<<"请停止你愚蠢的行为。"<<endl;exit(0);};
cout<<"请输入交易金额的下界和上界:"<<endl;
cin>>numbersize[0]>>numbersize[1];
if(numbersize[0] > numbersize[1]){cout<<"请停止你愚蠢的行为。"<<endl;exit(0);};
cout<<"那么我们来看看这一天中都发生了什么:"<<endl;
f = fopen("/home/crazy/2.6 银行业务模拟/当日业务记录.txt","w+");
fprintf(f,"相关参数:\n");
fprintf(f,"初始时银行现存总金额:%d元\n",total);
fprintf(f,"营业时间:%d分钟\n",closetime);
fprintf(f,"到达间隔时间的下界和上界:%d分钟 %d分钟\n",arrivedur[0],arrivedur[1]);
fprintf(f,"交易时间的下界和上界:%d分钟 %d分钟\n",solvedur[0],solvedur[1]);
fprintf(f,"交易金额的下界和上界:%d元 %d元\n",numbersize[0],numbersize[1]);
Banksim();
fprintf(f,"在这一天中用户逗留的平均时间:%f 分钟。\n",(float)totaltime / cusnum);
cout<<"在这一天中用户逗留的平均时间:"<<(float)totaltime / cusnum<<"分钟。"<<endl;
fclose(f);
cout<<"当日交易信息已写入记录文档。"<<endl;
return 0;
}