• 离散事件模型


    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
    ", 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
    ", 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("
    Total time is: %d min,average time is: %g min.
    ", 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("
    ");
    }
    
    void PrintEventList() {
    	//输出事件队列
    	printf("Current Eventlist is:
    ");
    	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
    ",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.
    ");
    		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.
    ");
    		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.
    ");
    		return ERROR;
    	}
    	while (p != NULL) {
    		printf("OccurTime:%d,Event Type:%d
    ", p->OccurTime, p->NType);
    		p = p->next;
    	}
    	printf("
    ");
    	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.
    ");
    		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.
    ");
    		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.
    ");
    		return ERROR;
    	}
    	while (p) {
    		printf("(%d,%d) ", p->ArriveTime, p->Duration);
    		p = p->next;
    	}
    	printf("
    ");
    	return OK;
    }
    

      

  • 相关阅读:
    Selenium常用API的使用java语言之7-控制浏览器操作
    Selenium常用API的使用java语言之6-WebDriver常用方法
    Selenium常用API的使用java语言之5-selenium元素定位
    Selenium常用API的使用java语言之4-环境安装之Selenium
    Selenium常用API的使用java语言之3-selenium3 浏览器驱动
    Selenium常用API的使用java语言之2-环境安装之IntelliJ IDEA
    ES6常用七大特性
    css实现类似朋友圈九宫格缩略图完美展示
    NodeJS入门篇
    viewport其实没那么难理解
  • 原文地址:https://www.cnblogs.com/lsh123/p/7413911.html
Copyright © 2020-2023  润新知