⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 logic.js

📁 单服务台排队系统仿真程序.该程序采用的是事件调度法
💻 JS
字号:
//声明全局变量
var evnStack = [];	//事件记录列表
var ifOutOfTime = false;		//是否超出指定的仿真时间范围

var nextTime = 0;		//下一到达时间
var customerNum = 0;	//系统中顾客数
var endTime = 0;		//离去时间
var hasServeNum = 0;	//已服务人数
var idleTime = 0;		//服务台闲期
var curStatus = ['闲', '忙', '闲->忙', '忙->闲'];		//服务台状态数组	0:闲 1:忙 2:闲->忙 3:忙->闲

var emulateTime;	//仿真时间长度
var minSpaceTime;	//两事件最短间隔时间
var maxSpaceTime;	//两事件最长间隔时间
var minServeTime;	//最短服务时间
var maxServeTime;	//最长服务时间

//如果没有设置参数,则参数默认
emulateTime = 500;
minSpaceTime = 1;
maxSpaceTime = 50;
minServeTime = 1;
maxServeTime = 30;

//开始仿真
function startEmluator() {
	varInitialization();

	//初始化事件,开始营业
	evnStack.push([0, null, null, null, null, null, 0, 0, null, null, null, null, null, 0, null]);

	//在指定时间范围内随机产生事件
	while (!ifOutOfTime)	//如果还未超出时间范围
		generateNextEvent();

	//最后停止营业
	pushEvent([nextTime, null, null, null, null, null, 0, 0, null, null, null, null, null, hasServeNum, null]);

	go('resultarea').value = outputResult();
}

//返回指定ID的对象
function go(id) {
	return document.getElementById(id);
}

//全局变量初始化
function varInitialization() {
	evnStack = [];
	ifOutOfTime = false;
	nextTime = 0;
	customerNum = 0;
	endTime = 0;
	hasServeNum = 0;
	idleTime = 0;
	//alert(emulateTime+':'+minSpaceTime+':'+maxSpaceTime+':'+minServeTime+':'+maxServeTime);
}

//产生下一到来事件及其对应的离开事件记录
function generateNextEvent() {
	var t_curTime = nextTime;	//当前仿真钟
	var t_reachTime = t_curTime + randomTime(minSpaceTime, maxSpaceTime);	//产生随机到达时间
	var t_startTime = endTime<t_curTime?t_curTime:endTime;	//服务开始时间
	var t_waitTime = endTime-nextTime>0 ? endTime-nextTime : 0;	//等待时间>=0
	var t_serveTime = randomTime(minSpaceTime, maxSpaceTime);	//产生随机服务时间

	var evn = new Array();
	evn = [t_curTime,						//仿真钟 = 上一到达事件的[下一到达时间]
		1,									//事件类型 1-到达				
		customerNum+hasServeNum+1,			//顾客编号 = 系统中的顾客数+已服务的顾客数+1
		t_curTime,							//到达时间 = 仿真钟
		t_reachTime,						//下一到达时间 = 到达时间+随机间隔时间
		curStatus[customerNum>0?1:2],		//服务台状态 原系统中顾客数>0 --忙 原系统中顾客数=0 --闲->忙
		customerNum,						//队长 = 系统中的顾客数
		customerNum+1,						//系统中顾客数
		t_startTime,						//服务开始时间 = 上一顾客离去时间 或 到达时间(当离去时间<到达时间)
		t_waitTime,							//等待时间 = 上一顾客离去时间-到达时间
		t_serveTime,						//服务时间 = 随机时间长度
		t_startTime+t_serveTime,			//离去时间 = 服务开始时间+服务时间
		t_waitTime+t_serveTime,				//逗留时间 = 等待时间+服务时间
		hasServeNum,						//已服务人数 在updateLeaveEvent中更新
		idleTime>0?idleTime:null];			//服务台闲期 idleTime在updateLeaveEvent中更新

	//将此到达事件压入事件列表
	pushEvent(evn);
	//产生它的离开事件
	generateNextLeaveEvent(evn);

	//更新系统全局变量
	nextTime = t_reachTime;			//下一顾客到达时间
	customerNum ++;				//系统中顾客数加 1
	endTime = endTime+t_serveTime;	//离去时间
	idleTime = null;	//闲期
	if (nextTime >= emulateTime) ifOutOfTime = true;	//超出时间范围

	//更新当前到达事件与下一到达事件间的所有离开事件 (系统中的顾客数, 已服务人数等)
	updateLeaveEvent(t_curTime, t_reachTime);
}

//产生某个到来事件的离开事件记录
function generateNextLeaveEvent(evn) {
	var levn = new Array();
	levn = [evn[11],	//仿真钟 = 离去时间
			2,			//事件类型 2-离开
			evn[2],		//顾客编号
			null,
			null,
			null,		//服务台状态 在updateLeaveEvent中更新
			null,		//队长 在updateLeaveEvent中更新
			null,		//系统中的顾客数 在updateLeaveEvent中更新
			null,
			null,
			null,
			evn[11],	//离去时间
			null,
			null,		//已服务人数 在updateLeaveEvent中更新
			null];
	//将此离开事件压入事件列表
	pushEvent(levn);
}

//更新指定时间范围内的离开事件
function updateLeaveEvent(start, end) {
	var evnArray = [];	//指定区间内的离开事件在事件列表中的下标
	for (var i=evnStack.length-1; i>=0; i--) {
		if (evnStack[i][1] == 2) {	//只判断离去事件
			if (evnStack[i][7] != null) break;	//如果已经更新,则代表前面的离开事件都已更新,退出循环
			if (evnStack[i][0] >= start && evnStack[i][0] <= end)	//选出在指定范围内的事件
				evnArray.push(i);
		}
	}
	for (var i=evnArray.length-1; i>=0; i--) {
		customerNum -= 1;	//系统中顾客数减 1
		hasServeNum += 1;	//已服务人数加 1
		evnStack[evnArray[i]][7] = customerNum;
		evnStack[evnArray[i]][13] = hasServeNum;
		evnStack[evnArray[i]][5] = curStatus[customerNum>0 ? 1 : (evnStack[evnArray[i]][0]>0 ? 3 : 0)];	//服务台状态 原系统中顾客数>0 --忙 原系统中顾客数=0且仿真钟<>0 --忙->闲 原系统中顾客数=0且仿真钟=0 --闲
		evnStack[evnArray[i]][6] = customerNum-1>0 ? customerNum-1 : 0;	//队长 = 系统中的顾客数-1 >=0
		if (evnStack[evnArray[i]][5] == curStatus[3] && i != evnStack.length)	//如果服务台状态 忙->闲 则更新下一到达事件的闲期 ^不能是最后一个事件,否则数组下标溢出
			idleTime = end-evnStack[evnArray[i]][0];	//保存服务台闲期
	}
}

//将事件记录压入数组并排序
function pushEvent(evn) {
	evnStack.push(evn);
	//按仿真钟从小到大排序
	evnStack.sort(function(a, b) {return a[0]-b[0]});
}

//产生一个界于两数之间的随机时间,包括边界
function randomTime(min, max) {
	return Math.floor(min+Math.random()*(max-min+1));
}

//输出仿真结果表
function outputResult() {
	var str;
	str = '仿真钟	类型	顾客	到达	下一到达	状态	队长	顾客数	开始	等待	服务	离去	逗留	已服务	闲期';
	for (var i=0; i<=evnStack.length-1; i++) {
		str = str + '\r\n';
		for (var j=0; j<=14; j++) {
			str = str + (evnStack[i][j]==null ? '--' : evnStack[i][j]);
			if (j != 14) str = str + '	';
		}
	}
	return str;
}

//输出统计结果
function outputStatics() {
	var t_totalQueueLength = 0;		//各次队长总和
	var t_totalCustomerNum = 0;		//各次系统中顾客数总和
	var t_totalWaitTime = 0;		//顾客等待时间总和
	var t_totalStayTime = 0;		//顾客逗留时间总和
	var t_totalServeTime = 0;		//顾客服务时间总和

	var avgQueueLength = 0;		//平均队长
	var maxQueueLength = 0;		//最大队长
	var avgCustomerNum = 0;		//系统中平均顾客数
	var avgWaitTime = 0;		//平均等待时间
	var avgStayTime = 0;		//平均逗留时间
	var avgServeTime = 0;		//平均服务时间
	var totalIdleTime = 0;		//服务器台总闲期
	var percentOfIdleTime = 0;	//闲期所占百分比
	var totalServeCustomer = 0;	//总服务顾客数

	//取得最后一个在指定时间范围内的事件的编号
	var stackLen = 0;
	for (var i=evnStack.length-1; i>=0; i--) {
		if (evnStack[i][0] <= emulateTime) {
			stackLen = i;
			break;
		}
	}

	//取得总服务顾客数
	for (var i=evnStack.length-1; i>=0; i--) {
		if (evnStack[i][13] != null) {
			totalServeCustomer = evnStack[i][13];
			break;
		}
	}

	for (var i=1; i<=stackLen; i++) {
		t_totalQueueLength += evnStack[i][6]*(evnStack[i][6]-evnStack[i-1][6]);
		t_totalCustomerNum += evnStack[i][7]*(evnStack[i][6]-evnStack[i-1][6]);
		t_totalWaitTime += evnStack[i][9];
		t_totalStayTime += evnStack[i][12];
		totalIdleTime += evnStack[i][14];
		if (evnStack[i][6] > maxQueueLength) maxQueueLength = evnStack[i][6];
	}

	t_totalServeTime = t_totalStayTime - t_totalWaitTime;

	avgQueueLength = Math.round(t_totalQueueLength/emulateTime);
	avgCustomerNum = Math.round(t_totalCustomerNum/emulateTime);
	avgWaitTime = t_totalWaitTime/totalServeCustomer;
	avgStayTime = t_totalStayTime/totalServeCustomer;
	avgServeTime = t_totalServeTime/totalServeCustomer;
	percentOfIdleTime = totalIdleTime*100/emulateTime;

	var returnStr;
	returnStr = '平均队长:' + avgQueueLength + '<br />'
				+ '最大队长:' + maxQueueLength + '<br />'
				+ '系统中平均顾客数:' + avgCustomerNum + '<br />'
				+ '平均等待时间:' + avgWaitTime.toFixed(2) + '<br />'
				+ '平均逗留时间:' + avgStayTime.toFixed(2) + '<br />'
				+ '平均服务时间:' + avgServeTime.toFixed(2) + '<br />'
				+ '服务器台总闲期:' + totalIdleTime + '<br />'
				+ '闲期所占百分比:' + percentOfIdleTime.toFixed(2) + '%<br />'
				+ '总服务顾客数:' + totalServeCustomer;

	return returnStr;
}

//事件结构定义
//仿真钟	事件类型	顾客	到达时间	下一到达时间	服务台状态	队长	系统中顾客数	服务开始时间	等待时间	服务时间	离去时间	逗留时间	已服务人数	服务台闲期

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -