银行叫号系统
系统要求:
- 五个服务窗口;
- 一个客户队列,按先后顺序排列;
- 显示每个窗口顺序号、等待人数、每个顾客得到服务等待时间与最后平均时间及总客户数;
数据结构设计
- 服务窗口 Windows
class Windows {
private:
windows_status status;
list<Customer> Customer_list;
public:
Windows();
void set_busy();
void set_avail();
void redin_customer(Customer &x);
bool is_avail();
int get_people_num();
double get_average_time();
};
- 客户结构体 Customer
class Customer {
public:
Customer(int num, int arr,int dur= get_random(RP));
int get_num();
int get_arrive_time();
int get_duration();
int get_wait_time();
void set_wait_time(int time);
private:
int num;
int arrive_time;//到达时间
int duration;//随机生成的离开时间
int wait_time;//计算得到等待时间
};
- 系统总控 System
class System {
private:
double AverageWaitTime;
Windows wins[5];
list<Event> event_list;
list<Customer> customer_list;
int current_time;
long int total_time;
Event* current_event;
void customerArrived();//顾客到达
void customerDone();//顾客离开
int get_avail_windows();//检索可利用窗口
public:
System(long int totaltime=10000) {
AverageWaitTime = 0;
Event begin(0);//第一个顾客到达
event_list.push_back(begin);
current_time = 0;
total_time = totaltime;
current_event = &(*event_list.begin());
}
double get_AverageWaitTime() {
return AverageWaitTime;
}
int get_current_time() {
return current_time;
}
void run();//运行
friend void insert_by_time(System& system, Event& event);
};
- 随机数获取 get_random();
double U_Random();
int get_random(int Lambda)
{
int k = 0;
long double p = 1.0;
long double l = exp(-Lambda);
srand((unsigned)time(NULL));
//printf("%1.5Lf\n", l);
while (p >= l)
{
double u = U_Random();
p *= u;
k++;
}
return k - 1;
}
double U_Random()
{
double f;
f = (float)(rand() % 100);
return f / 100;
}
困难与解决方法:
-
如何驱动
使用任务队列,将任务分为 a,顾客到达 b,顾客离开 。
在a任务中遍新顾客入队并进行判断,第一层判断其到达时间是否超过最大服务时间,没有则生成此顾客信息,进行第二层判断,是否有空闲窗口,若有空闲窗口,则进入窗口操作,若无,则进入顾客等待队列,待b任务发生时检索顾客等待队列以进入下一步操作。
在b任务中,顾客离开后对顾客等待队列进行检索,若有等待顾客则使队列首位(最先抵达)者进入窗口操作,若无,则置此窗口为空闲,等待顾客到达。
-
如何停止
规定给出一个服务末尾时间,入队操作发生时间晚于次时间则停止生成新顾客。
-
如何生成随机顾客队列
通过控制顾客到达时间间隔为随机达到实现随机顾客队列的目的。
编译调试环境:
- Visual Studio 2017
#ifndef Customer_hpp
#define Customer_hpp
#define RP 100//随机数参数,最大值
#include <cmath>
#include <cstdlib>
#include "random.hpp"
class Customer {
public:
Customer(int num, int arr,int dur= get_random(RP)) :
num(num),
wait_time(0),
arrive_time(arr),
duration(dur){}
int get_num() {
return num;
}
int get_arrive_time() {
return arrive_time;
}
int get_duration() {
return duration;
}
int get_wait_time() {
return wait_time;
}
void set_wait_time(int time) {
wait_time = time;
return;
}
private:
int num;
int arrive_time;//到达时间
int duration;//随机生成的离开时间
int wait_time;//计算得到等待时间
};
#endif
#ifndef random_hpp
#define random_hpp
#include <cstdlib>
#include <cmath>
#include <ctime>
//double get_random(double max = 1) {
// return ((double)std::rand() / (RAND_MAX))*max;
//}
double U_Random();
int get_random(int Lambda)
{
int k = 0;
long double p = 1.0;
long double l = exp(-Lambda);
srand((unsigned)time(NULL));
//printf("%1.5Lf\n", l);
while (p >= l)
{
double u = U_Random();
p *= u;
k++;
}
return k - 1;
}
double U_Random()
{
double f;
f = (float)(rand() % 100);
return f / 100;
}
#endif // !random_hpp
#ifndef Windows_hpp
#define Windows_hpp
#include <list>
#include "Customer.hpp"
using namespace std;
enum windows_status {
avail,
unavail
};
class Windows {
private:
windows_status status;
list<Customer> Customer_list;
public:
Windows():
status(avail){}
void set_busy() {
status = unavail;
}
void set_avail() {
status = avail;
}
void redin_customer(Customer &x) {
Customer_list.push_back(x);
}
bool is_avail() {
return !status;
}
int get_people_num() {
return Customer_list.size();
}
double get_average_time() {
if (Customer_list.size() == 0)
return 0;
double average=0;
list<Customer>::iterator iter = Customer_list.begin();
for (; iter != Customer_list.end(); iter++) {
average += iter->get_wait_time();
}
average = (double)average/Customer_list.size();
return average;
}
};
#endif // !Windows_hpp
#ifndef Event_hpp
#define Event_hpp
#define RP 100//Random maxmum
#include "random.hpp"
struct Event {
int occur_time;//事件发生时间
int type;// -1表示到达,只检索是否有空窗;属于[0,4]表示从0~4号窗口离开,置空闲
Event(int time = get_random(RP), int type = -1) :
occur_time(time),
type(type){}
};
#endif // !Event_hpp
#include <iostream>
#include "System.hpp"
#include <ctime>
#include <list>
using namespace std;
int main()
{
//srand(time(NULL));
System exam(10000);
exam.run();
}
#ifndef System_hpp
#define System_hpp
#include "Customer.hpp"
#include "Event.hpp"
#include "random.hpp"
#include "Windows.hpp"
#include <iomanip>
#include <list>
#include <vector>
#include <iostream>
using namespace std;
static int num = 1;
#define LT 99//至多办公时间(必在100内离开)
class System {
private:
double AverageWaitTime;
Windows wins[5];
list<Event> event_list;
list<Customer> customer_list;
int current_time;
long int total_time;
Event* current_event;
void customerArrived();//顾客到达
void customerDone();//顾客离开
int get_avail_windows();//检索可利用窗口
public:
System(long int totaltime=10000) {
AverageWaitTime = 0;
Event begin(0);//第一个顾客到达
event_list.push_back(begin);
//Event out(get_random(10), 0);
//event_list.push_back(out);
current_time = 0;
total_time = totaltime;
current_event = &(*event_list.begin());
}
double get_AverageWaitTime() {
return AverageWaitTime;
}
int get_current_time() {
return current_time;
}
void run();//运行
friend void insert_by_time(System& system, Event& event);//友元函数
};
void System::customerArrived() {
current_time = current_event->occur_time;
Customer x(num++, current_time);//生成一个顾客,到达时间为此事件发生时间,等待时间未设置
Event arrive(current_time + get_random(9)+1);//平均n+1/2到一个人
if (arrive.occur_time < total_time) {//(arrive.occur_time < total_time) 到达时间在关门前
insert_by_time(*this,arrive);//在约定时间(关闭服务)前插入到达事件
}
if (get_avail_windows() == -1) {//窗口已满
customer_list.push_back(x);//入顾客等待队列
}
else {//有空闲窗口
int k = get_avail_windows();//获取空闲窗口
int interim = get_random(LT)+1;//100单位时间内必定离开
int time = interim + current_time;
Event out(time, k);//生成离开事件
insert_by_time(*this,out);//离开事件入队!!!得按照事件先后入队
wins[k].redin_customer(x);
wins[k].set_busy();
cout << "Current Time:" << current_time << endl;
cout << "Windows'num :"<<k+1<<" "<<"Customer Num:" <<setw(5)<< x.get_num() << " " << "Wait_time: " << setiosflags(ios::fixed) <<setprecision(5)<< x.get_wait_time() << endl;
}
event_list.pop_front();//任务完成则出队
if (!event_list.empty())
current_event = &(*event_list.begin());
else
current_event = NULL;
}
//要想获取当前客户离开的窗口,窗口由事件结构体(event)表示出来
void System::customerDone() {//顾客离开
int k = current_event->type;
wins[k].set_avail();
current_time = current_event->occur_time;
event_list.pop_front();
if (!customer_list.empty()) {
list<Customer>::iterator iter = customer_list.begin();
iter->set_wait_time(current_time - iter->get_arrive_time());
wins[k].redin_customer(*iter);
wins[k].set_busy();
//cout << "DONE1!"<< endl;
cout << "Current Time:" << current_time << endl;
cout << "Windows'num :" << k +1<< " " << "Customer Num:" <<setw(5)<< iter->get_num() << " " << "Wait_time: " << setiosflags(ios::fixed) << setprecision(5) << iter->get_wait_time() << endl;
customer_list.pop_front();
int time = current_time + get_random(LT)+1;//生成下个离开事件
Event out(time, k);
insert_by_time(*this, out);//生成离开事件
}
//event_list.pop_front();//任务出队 !!! 错误:这里出队会导致可能存在新加的出队任务排第一而被出队
if (!event_list.empty())
current_event = &(*event_list.begin());
else
current_event = NULL;
}
int System::get_avail_windows() {
for (int i = 0; i < 5; i++) {
if (wins[i].is_avail()) {
return i;
}
}
return - 1;
}
void System::run() {
while (!event_list.empty()) {
//只是增加顾客,不进入Done会导致不进入下一步动作
if (current_event->type == -1)
customerArrived();
else
customerDone();
}
cout << endl << endl;
for (int i = 0; i < 5; i++) {
cout << "Windows'num :" << i +1<< " " << "Average Wait Time: " << setiosflags(ios::fixed) <<setprecision(5)<<wins[i].get_average_time() <<" Total Num of People: "<<setw(5)<<wins[i].get_people_num()<< endl;
AverageWaitTime += wins[i].get_average_time();
}
cout << "The Final Average Wait Time :" <<setprecision(5)<< AverageWaitTime / 5 << endl;
return;
}
//插入链表,按照time排序,用于事件插入
void insert_by_time(System& system, Event& event) {
list<Event>::iterator iter = system.event_list.begin();
if (system.event_list.empty()) {
system.event_list.push_back(event);
return;
}
while (iter!=system.event_list.end()&& event.occur_time > iter->occur_time)
iter++;
system.event_list.insert(iter, event);
}
#endif // !System_hpp