这节是银行业务模拟程序、
假设某银行有4个窗口对外接待客户,每个窗口接待一个人,当有人要办理业务的时候,如果某窗口空闲,则可办理,如果不空闲,则排在人最少的后面。现编制一个程序以模拟银行这种活动并计算一天中客户在银行逗留的平均时间。
为了计算这个平均时间,要掌握每个客户到达银行和离开银行这两个时刻,后者减去前者就是逗留时间。所有客户逗留时间的总和被一天内进入银行的客户数除便是所求的平均时间。
下面是银行业务模拟,统计一天内客户在银行逗留的平均时间:
代码如下:
void Bank_Simulation(int CloseTime){ OpenForDay(); //初始化 while (MoreEvent) { EventDrived(OccurTime, EventType); //事件驱动 switch (EventType) { case 'A':CustomerArrived(); break; case 'D':CustomerDeparture();break; default:Invalid(); } } CloseForDay();}下面分析下:1.这个OpenForDay可以理解成开启一个计时器,然后最后有CloseForDay()就是关闭计时器。
2.EventDrived(OccurTime,EventType)这个我们可以看见有个事件驱动,第一个参数是当前时间,第二个参数是事件类型。
3.这个事件类型有A,D,和其他,A代表Arrived,D代表Departure,其他事件缺省情况(默认情况)是无效的。
算法3.6:
模拟程序中有4个窗口业务窗口,所以要4个队列,对每个队头客户都存在一个将要驱动的客户离开事件。
因此在任何时刻即将发送的事件只有5种可能:
1.新的客户到达。
2.1号窗口客户离开。
3.2号窗口客户离开。
4.3号窗口客户离开。
5.4号窗口客户离开。
下面是有序链表和队列的结构体:
typedef struct{ int OccurTime; //事件发生时刻 int NType; //事件类型,0表示到达事件,1-4表示4个窗口的离开事件}Event,ElemType;typedef LinkList EventList; //事件链表类型,定义为有序链表typedef struct{ int ArrivalTime; //到达时刻 int Duration; //办理业务的时间}QElemType;由于在实际的银行中,客户到达的时刻以及办理事物所需时间都是随机的,在模拟程序中可用随机数来代替。假设第一个顾客进门的时刻为0,即是模拟程序处理的第一个事件,之后每个客户到达的时刻在前一个客户到达时设定。因此在客户达到事件发生时需先产生俩个随机数:其一为此时刻到达的客户办理事物所需时间durtime;其二为下一客户到达时间间隔imtertime,假设事件发生的时刻为Occurtime,则下一个客户到达的时刻为Occurtime+intertime。由此应产生一个新的客户到达事件插入事件表;刚到达的客户则应插入到当前所含元素最少的队列中;若插入前为空,则产生一个客户立刻事件插入事件表。客户离开事件的处理比较简单。首先计算该客户在银行逗留的时间,然后从队列中删除该客户后查看队列是否空,若空则设定一个新的队头客户离开事件。
算法如下所示:
// 程序中用到的主要变量EventList ev; // 事件表Event en; // 事件LinkQueue q[5]; // 4个客户队列,q[0]未用QElemType customer; // 客户记录int TotalTime, CustomerNum; // 累计客户逗留时间, 客户数int CloseTime;//---------------- 算法 3.7 ------------------int cmp(Event a, Event b) { // 依事件a的发生时刻< 或= 或> 事件b的发生时刻分别返回-1或0或1 if (a.OccurTime < b.OccurTime) return -1; if (a.OccurTime > b.OccurTime) return +1; return 0;}void Random(int &durtime, int &intertime) { // 生成随机数 durtime = random(2, 10); intertime = random(10);}int Minimum(LinkQueue q[]) { // 求长度最短队列 int minlen = QueueLength(q[1]); int i = 1; for (int j=2; j<=4; j++) if (QueueLength(q[j]) < minlen) { minlen = QueueLength(q[j]); i = j; } return i;}void OpenForDay() { // 初始化操作 TotalTime = 0; CustomerNum = 0; // 初始化累计时间和客户数为0 InitList(ev); // 初始化事件链表为空表 en.OccurTime = 0; en.NType = 0; // 设定第一个客户到达事件 OrderInsert(ev, en, cmp); // 按事件发生时刻的次序插入事件表 for (int i=1; i<=4; ++i) InitQueue(q[i]); // 置空队列} // OpenForDayvoid CustomerArrived() { // 处理客户到达事件,en.NType=0 int durtime, intertime, i, t; ++CustomerNum; PRintf("Customer %d arrived at %d and ", CustomerNum, en.OccurTime); Random(durtime, intertime); // 生成随机数 t = en.OccurTime + intertime; // 下一客户到达时刻 if (t<CloseTime) // 银行尚未关门,插入事件表 OrderInsert(ev, MakeElem(t, 0), cmp); i = Minimum(q); // 求长度最短队列 printf("enter the Queue %d/n", i); EnQueue(q[i], MakeQElem(en.OccurTime, durtime)); if (QueueLength(q[i]) == 1) //设定第i队列的一个离开事件并插入事件表 OrderInsert(ev, MakeElem(en.OccurTime+durtime, i), cmp);} // CustomerArrivedvoid CustomerDeparture() { // 处理客户离开事件,en.NType>0 printf("Customer departure at %d/n", en.OccurTime); int i = en.NType; DeQueue(q[i], customer); //删除第i队列的排头客户 TotalTime += en.OccurTime-customer.ArrivalTime; // 累计客户逗留时间 if (!QueueEmpty(q[i])) { // 设定第i队列的一个离开事件并插入事件表 GetHead (q[i], customer); OrderInsert(ev, MakeElem(en.OccurTime+customer.Duration, i), cmp); }} // CustomerDeparturevoid Bank_Simulation(int closetime) { int i = 0; BLink p; CloseTime = closetime; printf("Bank_Simulation( %d ) ----- 银行业务模拟/n", closetime); OpenForDay(); // 初始化 while (!ListEmpty(ev)) { printList(ev); if (DelFirst(GetHead(ev), p)) { en = GetCurElem(p); if (en.NType == 0) CustomerArrived(); // 处理客户到达事件 else CustomerDeparture(); // 处理客户离开事件 } if (++i % 9 == 0) { printf("/n----- 按任意键,继续 -----"); getch(); printf("/n/n"); } } // 计算并输出平均逗留时间 printf("/nThe Average Time is %f/n", (float)TotalTime/CustomerNum);} // Bank_Simulation
新闻热点
疑难解答