嚴蔚敏 資料結構C語言 銀行排隊佇列 離散事件模擬
阿新 • • 發佈:2019-01-28
系統每次隨機生成的是1)當前顧客顧客的櫃檯被服務時間2)當前顧客和下一個顧客到達的間隔時間,記住這2點就理解了整個程式碼,書裡說得不太清楚。每個顧客在銀行的等待時間取決於佇列裡前一個節點的離開時間,而不是自己的到達時間+服務時間。
程式碼設定了EventList這個事件連結串列 ,來儲存隨機生成的顧客到達時間和服務時間,模擬排隊業務。
不過現實生活中,顧客達到時間可以模擬,但是被服務時間一般不好模擬!不知道這樣的事件驅動模型在哪個實際場景中有用?
//離散事件模擬,模擬銀行營業時的排隊情況 //不考慮顧客中途離開,顧客到達事件隨機,業務辦理時間 //長度隨機,選擇最短的隊排隊,不再換隊 //作者:nuaazdh //時間:2011年12月10日 08:52:37 #include <stdio.h> #include <time.h> #include <stdlib.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 typedef int Status; typedef struct Event{ //事件型別 int OccurTime; //事件發生時刻 int NType; //事件型別,0表示到達事件,1至4表示四個視窗的離開事件 struct Event *next; }Event,ElemType; typedef struct{ //單向連結串列結構 ElemType *head;//頭指標 ElemType *tail;//尾指標 int len; //長度 }LinkList; typedef LinkList EventList; //事件連結串列 typedef struct QElemType{ //佇列元素 int ArriveTime;//到達時間 int Duration;//辦理業務所需時間 struct QElemType *next; }QElemType; typedef struct{//佇列結構 QElemType *head;//頭指標 QElemType *tail;//尾指標 }LinkQueue; Event NewEvent(int occurT,int nType); //根據OccurTime和NType值,建立新事件 Status InitList(LinkList *L); //初始化事件連結串列 Status OrderInsert(LinkList *L,Event e); //將事件e按發生時間順序插入有序連結串列L中 Status ListEmpty(LinkList *L); //判斷連結串列L是否為空,為空返回TRUE,否則返回FALSE Status DelFirst(LinkList *L,ElemType *e); //連結串列L不為空,刪除其首結點,用e返回,並返回OK;否則返回ERROR Status ListTraverse(LinkList *L); //遍歷連結串列 Status InitQueue(LinkQueue *Q); //初始化佇列Q Status EmptyQueue(LinkQueue *Q); //若佇列Q為空,返回TRUE,否則返回FALSE Status DelQueue(LinkQueue *Q,QElemType *e); //若佇列Q不為空,首結點出隊,用e返回,並返回OK;否則返回ERROR Status EnQueue(LinkQueue *Q,QElemType e); //結點e入隊Q int QueueLength(LinkQueue Q); //返回佇列Q的長度,即元素個數 Status GetHead(LinkQueue *Q,QElemType *e); //若佇列Q不為空,用e返回其首結點,並返回OK,否則返回ERROR Status QueueTraverse(LinkQueue *Q); //遍歷佇列Q //------------------// int Min(int a[],int n); //返回長度為n的陣列a第一個最小值的下標,從1開始 int ShortestQueue(); //獲取最短佇列的編號 void OpenForDay(); //初始化操作 void CustomerArrived(); //顧客達到事件 void CustomerDepature(); //顧客離開事件 void Bank_Simulation(); //銀行排隊模擬 void PrintEventList(); //輸出事件佇列 void PrintQueue(); //列印當前佇列 //----全域性變數-----// EventList ev; Event en; LinkQueue q[5]; QElemType customer; int TotalTime,CustomerNum; int CloseTime=200;//關閉時間,即營業時間長度 //--------------main()------------------// int main() { Bank_Simulation(); return 0; } //--------------模擬排隊----------------// void OpenForDay(){ //初始化操作 int i; TotalTime=0; CustomerNum=0; InitList(&ev);//初始化事件佇列 en.OccurTime=0; en.NType=0; OrderInsert(&ev,en); for(i=1;i<=4;i++) InitQueue(&q[i]);//初始化四個視窗佇列 }//OpenForDay void CustomerArrived(){ //顧客達到事件 int durtime,intertime,i,t; QElemType e; ++CustomerNum; intertime=rand()%5+1;//間隔時間在5分鐘內 durtime=rand()%30+1;//辦理業務時間在30分鐘內 t=en.OccurTime+intertime; if( en.OccurTime<CloseTime){//銀行尚未關門 printf("A new customer arrived at:%d,his durTime=%d,the next intertime=%d|\n",en.OccurTime,durtime,intertime);//下一位顧客達到時間 OrderInsert(&ev,NewEvent(t,0)); i=ShortestQueue();//最短佇列 e.ArriveTime=en.OccurTime; e.Duration=durtime; EnQueue(&q[i],e); if(QueueLength(q[i])==1) OrderInsert(&ev,NewEvent(en.OccurTime+durtime,i)); }else{ printf("maxinum exceed!stop,en.OccurTime=%d,intertime=%d\n",en.OccurTime,intertime); } } void CustomerDepature(){ //顧客離開事件 int i=en.NType; DelQueue(&q[i],&customer); printf("A customer leaves at:%d\n",en.OccurTime);//輸出顧客離開時間 TotalTime+=en.OccurTime-customer.ArriveTime; if(!EmptyQueue(&q[i])){ GetHead(&q[i],&customer); OrderInsert(&ev,NewEvent(en.OccurTime+customer.Duration,i)); } } void Bank_Simulation(){ //銀行排隊模擬 OpenForDay(); srand((unsigned)time(NULL)); while(!ListEmpty(&ev)){ DelFirst(&ev,&en); printf("--------action--------------------------\n"); if(en.NType==0) CustomerArrived(); else CustomerDepature(); PrintQueue(); PrintEventList(); } printf("\nTotal time is: %d min,average time is: %g min.\n",TotalTime,(float)TotalTime/CustomerNum); } void PrintQueue(){ //列印當前佇列 int i; for(i=1;i<=4;i++){ printf("Queue %d have %d customer(s):",i,QueueLength(q[i])); QueueTraverse(&q[i]); } printf("\n"); } void PrintEventList(){ //輸出事件佇列 printf("Current Eventlist is:\n"); ListTraverse(&ev); } int Min(int a[],int n){ //返回長度為n的陣列a第一個最小值的下標,從0開始 int i,tmp,ind=0; tmp=a[0]; for(i=1;i<n;i++){ if(a[i]<tmp){ tmp=a[i]; ind=i; } } return ind; } int ShortestQueue(){ //獲取最短佇列的編號 int i,a[4]; for(i=1;i<=4;i++){ a[i-1]=QueueLength(q[i]); //printf("隊%d的長度為%d\n",i,QueueLength(q[i])); } return Min(a,4)+1;//佇列從1開始編號 } //-----------隊和連結串列操作--------------// Event NewEvent(int occurT,int nType){ //根據OccurTime和NType值,建立新事件 Event e; e.OccurTime=occurT; e.NType=nType; return e; } Status InitList(LinkList *L){ //初始化事件連結串列 L->head=L->tail=(ElemType *)malloc(sizeof(ElemType)); if(!L->head){ printf("Apply for memory error.LinkList initialize failed.\n"); exit(0); } L->head->next=NULL; return OK; } Status OrderInsert(LinkList *L,Event e){ //將事件e按發生時間順序插入有序連結串列L中 ElemType *p,*q,*newptr; newptr=(ElemType *)malloc(sizeof(ElemType)); if(!newptr){ printf("Apply for memory error,new node can't insert intot the Eventlist.\n"); exit(0); } *newptr=e; if(TRUE==ListEmpty(L)){//連結串列為空 L->head->next=newptr; L->tail=newptr; L->tail->next=NULL; return OK; } q=L->head; p=L->head->next; while(p){//遍歷整個連結串列 if(p->OccurTime>=newptr->OccurTime) break; q=p; p=p->next; } q->next=newptr; newptr->next=p; if(!p)//插入位置為連結串列尾部 L->tail=newptr; return OK; } Status ListEmpty(LinkList *L){ //判斷連結串列L是否為空,為空返回TRUE,否則返回FALSE if((L->head==L->tail)&&(L->head!=NULL)) return TRUE; else return FALSE; } Status DelFirst(LinkList *L,ElemType *e){ //連結串列L不為空,刪除其首結點,用e返回,並返回OK;否則返回ERROR ElemType *p=L->head->next; if(!p) return ERROR; L->head->next=p->next; *e=*p; free(p); if(L->head->next==NULL) L->tail=L->head; return OK; } Status ListTraverse(LinkList *L){ //遍歷連結串列 Event *p=L->head->next; if(!p){ printf("List is empty.\n"); return ERROR; } while(p!=NULL){ printf("OccurTime:%d,Event Type:%d\n",p->OccurTime,p->NType); p=p->next; } printf("\n"); return OK; } Status InitQueue(LinkQueue *Q){ //初始化佇列Q Q->head=Q->tail=(QElemType *)malloc(sizeof(QElemType)); if(!Q->head){ printf("Apply for memory error.LinkQueue initialize failed.\n"); exit(0); } Q->head->next=NULL; return OK; } Status EmptyQueue(LinkQueue *Q){ //若佇列Q為空,返回TRUE,否則返回FALSE if(Q->head==Q->tail&&Q->head!=NULL) return TRUE; else return FALSE; } Status DelQueue(LinkQueue *Q,QElemType *e){ //若佇列Q不為空,首結點出隊,用e返回,並返回OK;否則返回ERROR QElemType *p=Q->head->next; if(!p) return ERROR; *e=*p; Q->head->next=p->next;//修正隊首指標 free(p); if(!Q->head->next)//隊空 Q->tail=Q->head; return OK; } Status EnQueue(LinkQueue *Q,QElemType e){ //結點e入隊Q QElemType *p=(QElemType *)malloc(sizeof(QElemType)); if(!p){ printf("Apply for memory error,new element can't enqueue.\n"); exit(0); } *p=e; p->next=NULL; Q->tail->next=p;//插入隊尾 Q->tail=p;//修改隊尾指標 return OK; } int QueueLength(LinkQueue Q){ //返回佇列Q的長度,即元素個數 int count=0; QElemType *p=Q.head->next; while(p){ p=p->next; count++; } return count; } Status GetHead(LinkQueue *Q,QElemType *e){ //若佇列Q不為空,用e返回其首結點,並返回OK,否則返回ERROR if(EmptyQueue(Q)) return ERROR; *e=*(Q->head->next); return OK; } Status QueueTraverse(LinkQueue *Q){ //遍歷佇列Q QElemType *p=Q->head->next; if(!p){ printf("--Is empty.\n"); return ERROR; } while(p){ printf("(%d,%d) ",p->ArriveTime,p->Duration); p=p->next; } printf("\n"); return OK; }