離散事件模型
阿新 • • 發佈:2017-08-23
模擬 nod unsigned del 指針 內容 lis 數組a 修改
0x01 代碼框架邏輯
模擬內容:
1.離散事件模擬,模擬銀行營業時的排隊情況
2.不考慮顧客中途離開,顧客到達事件隨機,業務辦理時間
3.長度隨機,選擇最短的隊排隊,不再換隊
代碼邏輯:
1.一個事件鏈表,四個窗口排隊隊列
2.事件驅動:每有一個新的顧客到達,將產生下一個新顧客到達的新事件按時間順序從小到大(OccurTime)插入事件鏈表(EventList) (如果此時窗口隊列只有 一個顧客,還將產生此顧客離開事件插入事件鏈表中)
每有一個顧客從某一隊列首離開,將產生他的後一位顧客離開的新事件按時間順序從小到大(OccurTime)插入事件鏈表(EventList)
#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 = 50;//關閉時間,即營業時間長度 //--------------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 (t<CloseTime) {//銀行尚未關門 printf("A new customer will arrive at:%d\n", en.OccurTime);//下一位顧客達到時間 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)); } } 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); //事件驅動 if (en.NType == 0) CustomerArrived(); else CustomerDepature(); //PrintEventList(); PrintQueue(); } 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; }
離散事件模型