模拟银行排队 BankQueuing

/****************************************
 *                                      *
 * 文件夹: ▲03 栈和队列\09 BankQueuing *
 *                                      *
 * 文件名: BankQueuing.h                *
 *                                      *
 * 内  容: 模拟银行排队相关操作列表     *
 *                                      *
 ****************************************/

#ifndef BANKQUEUING_H
#define BANKQUEUING_H

#include <stdio.h>
#include <stdlib.h>						//提供malloc、realloc、free、exit原型
#include <time.h>						//提供time原型
#include "../../▲01 绪论/Status.h"		//**▲01 绪论**//

/* 宏定义 */
#define SleepTime 1						//SleepTime代表休眠时间
#define DurationTime 20					//办理业务持续时间从1到DurationTime分钟不等 
#define IntervalTime 10					//下一个客户到来时间间隔为1到IntervalTime分钟不等 

/* 类型定义 */
typedef enum
{
	Arrive,Leave_1,Leave_2,Leave_3,Leave_4
}EventType;								//事件类型,0代表到达事件,1至4表示四个窗口的离开事件
typedef struct         					//事件链表                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          
{
	int OccurTime;						//事件发生时刻
	EventType NType;					//事件类型
}Event;
typedef Event LElemType_L;				//事件链表元素 
typedef struct LNode
{
	LElemType_L data;
	struct LNode *next;
}LNode; 
typedef LNode* LinkList;
typedef LinkList EventList;											//事件链表类型,定义为有序链表
#include "../../▲02 线性表/04 SinglyLinkedList/SinglyLinkedList.c"	//**▲02 线性表**//
typedef struct
{
	int ArrivedTime;					//客户到达时间
	int Duration;						//办理事务所需的时间
	int Count;							//此变量记录来到每个队列的客户是第几个
}QElemType_L;							//队列的数据元素类型 
#include "../07 LinkQueue/LinkQueue.c"	//**▲03 栈和队列**//

/* 全局变量 */
int gTotalTime, gCustomerNum;			//累计客户逗留时间,客户数
int gCloseTime = 480;					//关门时间,假设银行每天营业8小时,480分 
EventList gEv;							//事件表
Event gEn;								//事件
LinkQueue gQ[5];						//4个客户队列,0号单元弃用
QElemType_L gCustomerRcd;				//客户记录 
 
/* 模拟银行排队函数列表 */
void Bank_Simulation_1();
/*━━━━━━━━━━━━━━━━┓
┃(01)算法3.6:模拟银行排队事件。 ┃
┗━━━━━━━━━━━━━━━━*/

void OpenForDay();
/*━━━━━━━━━━━━━━┓
┃(02)银行开门,初始化各变量。┃
┗━━━━━━━━━━━━━━*/

Status MoreEvent();
/*━━━━━━━━━━━━┓
┃(03)判断事件表是否为空。┃
┗━━━━━━━━━━━━*/

void EventDrived(char *event);
/*━━━━━━━━━━━━━━━━┓
┃(04)事件驱动,获取当前事件类型。┃
┗━━━━━━━━━━━━━━━━*/

void CustomerArrived();
/*━━━━━━━━━━━┓
┃(05)处理客户到达事件。┃
┗━━━━━━━━━━━*/

void CustomerDeparture();
/*━━━━━━━━━━━┓
┃(06)处理客户离开事件。┃
┗━━━━━━━━━━━*/

void Invalid();
/*━━━━━━━━━┓
┃(07)事件类型错误。┃
┗━━━━━━━━━*/

void CloseForDay();
/*━━━━━━━┓
┃(08)银行关门。┃
┗━━━━━━━*/

int cmp(Event a, Event b);
/*━━━━━━━━━━━━━━━━┓
┃(09)比较事件a和b发生的先后次序。┃
┗━━━━━━━━━━━━━━━━*/

void Random(int *durtime, int *intertime);
/*━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃(10)生成随机数,包括当前客服办理业务所需时间和下一客户到达间隔的时间。┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━*/

Status OrderInsert(EventList gEv, Event gEn, int(cmp)(Event,Event));
/*━━━━━━━━━━━━━━━┓
┃(11)将事件插入事件表正确位置。┃
┗━━━━━━━━━━━━━━━*/

int Minimum();
/*━━━━━━━━━━━━━┓
┃(12)求长度最短队列的序号。┃
┗━━━━━━━━━━━━━*/

void Show();
/*━━━━━━━━━━━━━━━━┓
┃(13)显示当前队列的客户排队情况。┃
┗━━━━━━━━━━━━━━━━*/

void Bank_Simulation_2();
/*━━━━━━━━━━━━━━━━┓
┃(14)算法3.7:模拟银行排队事件。 ┃
┗━━━━━━━━━━━━━━━━*/

#endif
/****************************************
 *                                      *
 * 文件夹: ▲03 栈和队列\09 BankQueuing *
 *                                      *
 * 文件名: BankQueuing.c                *
 *                                      *
 * 算  法: 3.6、3.7                     * 
 *                                      *
 ****************************************/

#ifndef BANKQUEUING_C
#define BANKQUEUING_C

#include "BankQueuing.h" 				//**▲03 栈和队列**//

/*════╗
║ 算法3.6║ 
╚════*/
void Bank_Simulation_1()				//银行业务模拟,统计一天内客户在银行逗留的平均时间 
{
	char eventType;
	
	OpenForDay();						//初始化

	while(MoreEvent())
	{
		EventDrived(&eventType);		//事件驱动
		
		switch(eventType)
		{
			case 'A': 
				CustomerArrived();
				break;
			case 'D': 
				CustomerDeparture();
				break;
			default : 
				Invalid();
		}
	}
	
	CloseForDay();
}
 
void OpenForDay() 
{	
	int i;
	
	gTotalTime = 0;					//初始化累计时间和客户数为0 
	gCustomerNum = 0;
			
	InitList_L(&gEv);				//初始化事件链表为空表

	gEn.OccurTime = 0;				//设定第一个客户到达事件 
	gEn.NType = Arrive;
	 
	OrderInsert(gEv, gEn, cmp);		//插入事件表
	
	for(i=1; i<=4; ++i) 
		InitQueue_L(&gQ[i]);		//置空队列

	Show();
}

Status MoreEvent()
{
	if(!ListEmpty_L(gEv))
		return TRUE;
	else
		return FALSE;
}

void EventDrived(char *event)
{
	ListDelete_L(gEv, 1, &gEn);
	
	if(gEn.NType==Arrive)
		*event = 'A';
	else
		*event = 'D';
}

void CustomerArrived()							//处理客户到达事件,gEn.NType=0 
{	
	int durtime, intertime; 
	int cur_LeftTime, suc_ArrivalTime;
	int i;
	
	++gCustomerNum;								//总客户数增一 
	
	Random(&durtime, &intertime);				//生成当前客户办理业务需要的时间和下一个客户达到时间间隔
	cur_LeftTime    = gEn.OccurTime + durtime;	//当前客户的离开时间 
	suc_ArrivalTime = gEn.OccurTime + intertime;//下一个客户到达时间 
			
	gCustomerRcd.ArrivedTime = gEn.OccurTime;	//记录当前客户信息 
	gCustomerRcd.Duration    = durtime;
	gCustomerRcd.Count       = gCustomerNum;

	i = Minimum(gQ);							//求长度最短队列
	EnQueue_L(&gQ[i], gCustomerRcd); 			//当前客户进入最短队列
	Show();
	
	if(suc_ArrivalTime<gCloseTime)				//银行尚未关门,将下一客户到达事件插入事件表
	{
		gEn.OccurTime = suc_ArrivalTime;		//gEn的参数已经改变 
		gEn.NType = Arrive;
		OrderInsert(gEv, gEn, cmp);
	}

	if(QueueLength_L(gQ[i])==1)					//设定第i队列的队头客户的离开事件并插入事件表
	{
		gEn.OccurTime = cur_LeftTime;
		gEn.NType = i;		
		OrderInsert(gEv, gEn, cmp);					
	}
}

void CustomerDeparture()						//处理客户离开事件,gEn.NType>0
{
	int i = gEn.NType;
	
	DeQueue_L(&gQ[i], &gCustomerRcd);			//删除第i队列的排头客户
	Show();
		
	gTotalTime += gEn.OccurTime - gCustomerRcd.ArrivedTime;	//累计客户逗留时间
	
	if(!QueueEmpty_L(gQ[i]))					//设定第i队列的第一个离开事件并插入事件表 
	{
		GetHead_L(gQ[i], &gCustomerRcd);
		gEn.OccurTime += gCustomerRcd.Duration;
		gEn.NType = i;
		OrderInsert(gEv,gEn,cmp);
	} 
}

void Invalid()
{
	printf("运行错误!");
		exit(OVERFLOW);
}

void CloseForDay()
{
	printf("当天总共有%d个客户,平均逗留时间为%d分钟。\n",gCustomerNum,gTotalTime/gCustomerNum);
}

int cmp(Event a, Event b)					//比较两事件发生次序 
{
	if(a.OccurTime<b.OccurTime)				//a晚于b发生 
		return -1;
	if(a.OccurTime==b.OccurTime)			//a、b同时发生 
		return 0;
	if(a.OccurTime>b.OccurTime)				//a早于b发生 
		return 1;
}

void Random(int *durtime, int *intertime)
{
	srand((unsigned)time(NULL));
	*durtime = rand()%DurationTime+1;		//办业务时间持续1到20分钟
	*intertime = rand()%IntervalTime+1; 	//下一个顾客来的时间为间隔1到10分钟 
}

Status OrderInsert(EventList gEv, Event gEn, int (cmp)(Event,Event))
{
	int i;
	EventList p, pre, s;
	
	pre = gEv;
	p = gEv->next;							//p指向第一个事件 
	
	while(p && cmp(gEn, p->data)==1)		//查找gEn在事件表中应该插入的位置
	{
		pre = p;
		p = p->next;
	}
	
	s = (LinkList)malloc(sizeof(LNode));
	if(!s)
		exit(OVERFLOW);
	
	s->data = gEn;							//将gEn插入事件表
	s->next = pre->next;
	pre->next = s;
	
	return OK;
}

int Minimum()
{
	int i1 = QueueLength_L(gQ[1]);
	int i2 = QueueLength_L(gQ[2]);
	int i3 = QueueLength_L(gQ[3]);
	int i4 = QueueLength_L(gQ[4]);
	
	if(i1<=i2 && i1<=i3 && i1<=i4)
		return 1;
	if(i2<i1  && i2<=i3 && i2<=i4)
		return 2;
	if(i3<i1  && i3<i2  && i3<=i4)
		return 3;
	if(i4<i1  && i4<i2  && i4<i3 )
		return 4;
}

void Show()
{
	int i;
	QueuePtr p;								//记录到来的客户是第几个 
	
	system("cls");
	
	for(i=1; i<=4; i++)
	{
		for(p=gQ[i].front; p; p=p->next)
		{
			if(p==gQ[i].front)
			{
				if(i==1)
					printf("柜台①●");
				if(i==2)
					printf("柜台②●");
				if(i==3)
					printf("柜台③●");
				if(i==4)
					printf("柜台④●");
			}
			else
				printf("(%03d)",p->data.Count);			

	
			if(p==gQ[i].rear)
				printf("\n"); 
		}
	}
	
	Wait(SleepTime);
}

/*════╗
║ 算法3.7║ 
╚════*/
void Bank_Simulation_2()
{
	OpenForDay();							//初始化
	
	while(!ListEmpty_L(gEv))
	{
		ListDelete_L(gEv, 1, &gEn);
		
		if(gEn.NType==Arrive)
			CustomerArrived();				//处理客户到达事件 
		else
			CustomerDeparture();			//处理客户离开事件 
	}
	
	printf("当天总共有%d个客户,平均逗留时间为%d分钟。\n",gCustomerNum,gTotalTime/gCustomerNum);//计算平均逗留时间	
}

#endif
/****************************************
 *                                      *
 * 文件夹: ▲03 栈和队列\09 BankQueuing *
 *                                      *
 * 内  容: 模拟银行排队相关函数测试     *
 *                                      *
 ****************************************/

#include "BankQueuing.c"			//**▲03 栈和队列**//

int main(int argc, char **argv)
{
	getchar();
	Bank_Simulation_1();			//算法3.6	

//	Bank_Simulation_2();			//算法3.7,另一种算法 
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_42815188/article/details/87826479