1. 程式人生 > >離散事件模擬實驗

離散事件模擬實驗

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

typedef struct
{
	int OccurTime; //事件發生時刻;
	int NType;     //0表示到達事件,1~4表示四個視窗的離開事件
}Event;            //事件型別,有序連結串列LinkList的資料元素型別

typedef struct ENode  //事件連結串列型別
{
	Event data;
	struct ENode *next;
}ENode,*EventList;

typedef struct
{
	int ArrivalTime;  //到達銀行時間
	int Duration;     //辦理事務所需時間
}QElemType;           //佇列的資料元素型別

typedef struct QNode
{
	QElemType data;
	struct QNode *next;
}QNode,*QueuePtr;

typedef struct
{
	QueuePtr front;  //隊頭指標
	QueuePtr rear;   //隊尾指標
	int num;
}LinkQueue;

int TotalTime;     //記錄客戶總逗留時間
int CustomerNum;   //記錄總的客戶
int CloseTime=9;  //銀行關門時間初始化為22點

//函式原型宣告: 
void InitList(EventList &ev);                       //構造空表
void InitQueue(LinkQueue &Q);                       //構造空佇列
void OpenForDay(EventList &ev,LinkQueue Q[5]);      //初始化操作
void CustomerArrived(EventList &ev,LinkQueue Q[5],Event en); //客戶到達函式
int Minimum(LinkQueue Q[5]);                        //找幾個中佇列人數最少的那隊
int ListEmpty(EventList ev);                        //判斷事件表是否為空;
void Delfirst(EventList &ev,Event &p);
void Bank_Simulation(EventList &ev,LinkQueue Q[5]);
void CustomerDeparture(EventList &ev,LinkQueue Q[5],Event en);
void DelQueue(LinkQueue &Q,QElemType &customer); //刪除隊頭元素
int QueueEmpty(LinkQueue Q);                     //判斷空佇列函式
void GetHead(LinkQueue Q,QElemType &customer);   //取隊頭元素
void EnQueue(LinkQueue &Q,int n,int m);          //在隊尾插入元素
int QueueLength(LinkQueue Q);                    //求佇列長度
void OrderInsert(EventList &ev,Event en);
void show(EventList ev);
void ShowQ(LinkQueue Q);

//主函式
int main()
{
    EventList ev;
	LinkQueue Q[5];
	//******************
	Bank_Simulation(ev,Q);
	return 0;
}

//*
void Bank_Simulation(EventList &ev,LinkQueue Q[5])
{
    //*****************
	int n=5;
	OpenForDay(ev,Q);   //初始化
	Event p;
	while(ListEmpty(ev)!=1)   //條件事件表不空
	{
		printf("*********************************\n");
		Delfirst(ev,p);                            //刪除第一個事件,資訊存放在p中
//ok	printf("1=%d  ",p.NType);	printf("2=%d\n",p.OccurTime);
		if(p.NType==0)
		{
			CustomerArrived(ev,Q,p);               //=0,則處理客戶到來事件
		}
		else CustomerDeparture(ev,Q,p);            //>0則處理客戶離開事件
		show(ev);
		printf("[到銀行的時間.辦事時間]:\n");
		for(int j=1;j<=4;j++)
		{
			ShowQ(Q[j]);		
		}
	}
	printf("客戶總數: %d\n",CustomerNum);
	printf("客戶逗留總時間: %d\n",TotalTime);
	printf("平均時間: %f\n",(float)TotalTime/CustomerNum);
}

//處理客戶到達事件,en.NType=0;
void CustomerArrived(EventList &ev,LinkQueue Q[5],Event en)
{ 
	srand(time(0));
	int durtime;                 //辦理業務的時間
	int intertime;               //下一位客戶的間隔時間
	int i; //數量最少的佇列
	Event x,y;
	CustomerNum++;               //客戶總數+1;
//test	printf("客戶總數:%d\n",CustomerNum);
	durtime=rand()%5+1;        //範圍在1~100之間
	printf("業務時間:%d\n",durtime);
	intertime=rand()%2+1;
	printf("間隔時間:%d\n",intertime);
	x.OccurTime=en.OccurTime+intertime;    //下一個使用者到達的時間
	printf("下一個使用者到達的時間:%d\n",x.OccurTime);
	x.NType=0;
	if(x.OccurTime<CloseTime)
	{
		OrderInsert(ev,x);//插入事件表
	}
	i=Minimum(Q);                //求長度最短佇列
	EnQueue(Q[i],en.OccurTime,durtime);  //入隊
	y.NType=i;
//	printf("哪一個佇列=%d\n",y.NType);
	y.OccurTime=en.OccurTime+durtime;
	printf("使用者離開時間=%d\n",y.OccurTime);
//	printf("Q[i].num=%d\n",Q[i].num);
	if(Q[i].num==1)
	{
		OrderInsert(ev,y);//設定第i佇列的一個離開事件並插入事件表
	}
	return ;
}


//處理客戶離開事件 en.NType>0
void CustomerDeparture(EventList &ev,LinkQueue Q[5],Event p)
{
//	printf("p.NType=%d\n",p.NType);
	int i=p.NType;
	Event x;
	QElemType customer;
	DelQueue(Q[i],customer);  //刪除第i佇列的排頭客戶
	TotalTime+=p.OccurTime-customer.ArrivalTime;  //累計客戶逗留時間
//	printf("客戶總逗留時間:%d\n",TotalTime);
	if(Q[i].front!=Q[i].rear)   //若佇列不空,設定一個新的隊頭客戶離開事件
	{
		GetHead(Q[i],customer);
		x.NType=i;
		x.OccurTime=p.OccurTime+customer.Duration;
		printf("%d %d\n",x.NType,x.OccurTime);
		OrderInsert(ev,x);
	}
}

//取某一隊的隊頭元素函式
void GetHead(LinkQueue Q,QElemType &customer)
{
	customer=Q.rear->data;
}

//刪除隊頭元素
void DelQueue(LinkQueue &Q,QElemType &customer)
{
	if(Q.front==Q.rear)
	{
		printf("該佇列為空!\n");
		return;
	}
	QueuePtr p;
	p=Q.front->next;
	customer=p->data;
	Q.front->next=p->next;
	Q.num--;
	if(Q.rear==p) Q.rear=Q.front;
	free(p);
}


//刪除事件表中第一個事件,資訊存在p中
void Delfirst(EventList &ev,Event &p)
{
	if(ev->next==NULL) return;
	else
	{
		p=ev->next->data;
		ev->next=ev->next->next;
	}
}



//尋找人數最少佇列
int Minimum(LinkQueue Q[5])
{
	int i;
    int min=1;
    for(i=1;i<=4;i++)
	{
		if(Q[min].num>Q[i].num)
		{
			min=i;
		}
	}
	return min;
}

//構造空表函式ok1
void InitList(EventList &ev)
{
	EventList en;
	ev=(EventList)malloc(sizeof(ENode));
	if(ev==NULL)
	{
		printf("構建空表失敗!");
		exit(0);
	}
	ev->next=NULL;
	en=(EventList)malloc(sizeof(ENode));
	en->data.NType=0;
	en->data.OccurTime=0;
	en->next=ev->next;
	ev->next=en;	
}

//初始化函式ok2
void OpenForDay(EventList &ev,LinkQueue Q[5]) 
{
	int i;
	Event en;
	TotalTime=0;  //初始化客戶總逗留時間為0;
	CustomerNum=0; //初始化總的客戶數量為0;
	InitList(ev); //構建空表;
	ev->data.OccurTime=0; //設定第一個客戶到達事件
	ev->data.NType=0;
	en.NType=0;
	en.OccurTime=0;
	OrderInsert(ev,en);
    for(i=1;i<=4;i++)  //構造空佇列
	{
		InitQueue(Q[i]);
//test		ShowQ(Q[i]);
	}
}

//在事件表插入元素ok3
void OrderInsert(EventList &ev,Event en)
{
	EventList p;
  	EventList q=ev;
	p=(EventList)malloc(sizeof(ENode));
	p->data.NType=en.NType;
	p->data.OccurTime=en.OccurTime;
	while(q->next!=NULL)
	{
		if(q->next->data.OccurTime==0 ||en.OccurTime<q->next->data.OccurTime)
		{
            p->next=q->next;
			q->next=p;
			return;
		}
		else
		{
			q=q->next;
		}
	}
	return;
}

//展示事件表函式ok4
void show(EventList ev)
{
	while(ev->next->next)
	{
		printf("事件發生時間:%d",ev->next->data.OccurTime);
		printf("  事件型別:%d\n",ev->next->data.NType);
		ev=ev->next;
	}
}

//判斷事件表是否為空ok5
int ListEmpty(EventList ev)
{
	if(ev->next->next==NULL) return 1;
	else return 0;
}

//構造空佇列函式ok6
void InitQueue(LinkQueue &Q)
{
	Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode));
	if(Q.front==NULL)
	{
		printf("構造空佇列失敗!\n");
		exit(0);
	}
	Q.front->next=NULL;
	Q.rear->next=Q.front->next;
	Q.num=0;
}

//判斷佇列是否為空ok7
int QueueEmpty(LinkQueue Q)
{
	if(Q.front==Q.rear) return 1;
	else return 0;
}

//在某一隊中隊尾插入元素ok8
void EnQueue(LinkQueue &Q,int n,int m)
{
	QueuePtr p;
	p=(QueuePtr)malloc(sizeof(QNode));
	if(!p)
	{
		printf("分配記憶體失敗!");
		exit(0);
	}
	p->data.ArrivalTime=n;
	p->data.Duration=m;
	p->next=NULL;
	Q.rear->next=p;
	Q.rear=p;
	Q.num++;
}

//展示佇列函式ok9
void ShowQ(LinkQueue Q)
{
	
	if(Q.front==Q.rear)
	{
		printf("列印佇列為空!\n");
		return;
	}
	do
	{
		printf("[%d:",Q.front->next->data.ArrivalTime);
		printf("%d]    ",Q.front->next->data.Duration);
		Q.front=Q.front->next;
	}while(Q.rear->next!=Q.front->next);
	printf("\n");
	return;
}