银行业务模拟

一道闹心的数据结构作业,请读者仔细读题,理清思路,这个问题的逻辑有点绕。



/****************************************************
文件名:事件驱动模拟
创建人:张劲暾(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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值