這節是銀行業務模擬程序、
假設某銀行有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
新聞熱點
疑難解答