离散事件模拟

离散事件模拟

July 10, 2010
/* by SonicRang */

#include <iostream>  
#include <stdlib.h>  
#include <time.h>  
#include <windows.h>

using namespace std;

#define WINDOW 5 //定义服务窗口个数

/* 定义各窗口服务队列 */

typedef struct qnode
{
	int arrivetime; //到达时刻  
	int duration; //处理时长  
	struct qnode *next;
}Qnode, *Queptr;


typedef struct
{
	Qnode *front, *rear;
	int length;
}LinkQueue;

/* 定义结束 */

/* 定义一天内所有事件链表 */
typedef struct enode
{
	int occurTime, NType; //事件发生时刻,事件类型(0:未发生 非0:已完成)  
	struct enode *next;
}Enode, *Eptr;

typedef struct
{
	Enode *front, *rear;
	int eventNum; //事件数  
}EventList;

/* 定义结束 */


/* 定义全局变量 */

EventList *eventlist; //事件链表  
LinkQueue q[WINDOW + 1]; //窗口队列  
Eptr pe, ev; //事件节点

int seed = 300;
int closetime; //银行工作时长  
int totaltime; //总时间  
int customerNum; //客流量  

/* 定义结束 */



/* 插入客户事件到事件链表 */

void InsertEvent(EventList *eventlist, int Time, int Type)
{
	Eptr p, q, location;
	p = new Enode;
	p->occurTime = Time;
	p->NType = Type;
	eventlist->eventNum++;
	q = eventlist->front;
	location = NULL;


	while (q && (Time > q->occurTime)) //找到插入位置  
	{
		location = q;
		q = q->next;
	}


	if (location == NULL) //找到了空队列插入到队头  
	{
		p->next = eventlist->front;
		eventlist->front = p;
	}
	else //找到了非空队列插入到队尾  
	{
		p->next = q;
		location->next = p;
	}


	if (eventlist->eventNum == 1) //初始化队尾  
	{
		eventlist->rear = p;
	}
}

/* 插入完成 */



/* 删除事件链表中的事件 */
void DeletEvent(EventList *ev, Eptr &data)
{
	Eptr p;
	p = ev->front;
	ev->front = p->next;
	if (--ev->eventNum<1)
	{
		ev->rear = ev->front;
	}
	data = p;
}

/* 删除完成 */



/* 当前客户插入窗口队列 */
void EnQueue(LinkQueue *q, int t1, int t2)
{
	Queptr p;
	p = new Qnode;
	p->arrivetime = t1;
	p->duration = t2;
	q->length++;
	if (q->length == 1) //只有一个元素的队列处理  
	{
		p->next = NULL;
		q->front = q->rear = p;
	}
	else
	{
		p->next = q->rear->next;
	}
	q->rear->next = p;
	q->rear = p; //重连接队列  
}
/* c插入完成 */


/* 当前客户出窗口队列进行处理 */
void DeQueue(LinkQueue *q, Queptr f)
{
	Queptr p;
	if (q->length>0)
	{
		f->arrivetime = q->front->arrivetime;
		f->duration = q->front->duration;
		p = q->front;
		q->front = q->front->next;
		q->length--;
		if (q->length == 0)
			q->rear = NULL;
		delete (p);
	}
}
/* 处理结束 */



/* 找最短队列 */
int Minlength()
{
	int min, j, i;
	min = q[1].length;
	j = 1;
	for (i = 2; i <= WINDOW; i++)
		if (q[i].length < min)
		{
			min = q[i].length;
			j = i;
		}
	return j;
}
/* 查询完成 */


/* 初始化银行 */
void Open()
{
	int i;
	eventlist = new EventList;
	pe = new Enode;
	pe->occurTime = 0; //初始化发生事件事件  
	pe->NType = 0;
	pe->next = NULL;
	eventlist->front = pe; //插入第一个客户到事件表  
	eventlist->rear = pe;
	eventlist->eventNum = 1;


	for (i = 1; i < WINDOW + 1; i++) //初始化服务窗口队列为空  
	{
		q[i].front = q[i].rear = NULL;
		q[i].length = 0;
	}
}
/* 初始化结束 */


/* 客户到达 */
void CustomerArrived()
{
	int durtime, intertime, min;
	customerNum++; //客流量增加  

	srand((unsigned)time(NULL));

	Sleep(1000);
	durtime = 5 + rand() % 31; //产生随机数(当前客户所需的服务时间和下一个用户到达的时间间隔)  
	intertime = 5 + rand() % 11;


	if ((ev->occurTime + intertime) < closetime)
		InsertEvent(eventlist, ev->occurTime + intertime, 0); //下一个客户到事件加入事件表

	min = Minlength(); //找最短队列  
	EnQueue(&q[min], ev->occurTime, durtime); //客户加入窗口


	cout << "客户于<" << ev->occurTime << ">时刻进入" << min << "号窗口," << "处理了" << durtime << "分钟" << endl;

	if (q[min].length == 1)
		InsertEvent(eventlist, ev->occurTime + durtime, min); //唯一客户加入离开事件  
}
/* 函数结束 */



/* 客户离开 */
void CustomerLeave()
{
	int i;
	i = ev->NType; //第i号窗的客户离开  
	Queptr data;
	data = new Qnode;
	DeQueue(&q[i], data); //删除i号窗口的排头客户

	cout << i << "号窗口客户离开" << endl;

	totaltime += ev->occurTime - data->arrivetime; //总时间累积

	if (q[i].length != 0) //插入离开事件  
		InsertEvent(eventlist, ev->occurTime + q[i].front->duration, i);
}
/* 函数结束 */



/* 主函数 */
void main()
{
	cout << "**************银行模拟系统**************" << endl;
	cout << "请输入银行营业时长(分钟):" << endl;
	cin >> closetime;

	Open(); //初始化银行

	while (eventlist->eventNum > 0) //事件非空开始执行  
	{
		DeletEvent(eventlist, ev); //取事件表中的第一个事件节点  

		if (ev->NType == 0) //处理客户到达事件  
			CustomerArrived();

		else
			CustomerLeave(); //处理离开事件  
	}

	cout << "今日客流量:" << customerNum << endl;
	cout << "平均处理时间:" << totaltime / customerNum << "分钟" << endl;
	system("pause");
}
最后更新于