代码如下:
//queue.h
#ifndef QUEUE_H_
#define QUEUE_H_
//顾客类
class Customer{
private:
long arrive;//顾客到达时间
int processtime;//顾客受理时间
public:
Customer(){arrive = processtime = 0;}//构造函数 初始化为0
void set(long when);//设定顾客到达时间和受理时间
long when() const{return arrive;}//返回到达时间的函数
int ptime() const{return processtime;} //返回受理时间的函数
};
typedef Customer Item;//使用Item代替Customer更为简便
//队列类
class Queue{
private:
struct Node{Item item;struct Node * next;};//建立链表节点 内容包括顾客类和指向下个节点的指针
enum{Q_SIZE = 10};//利用枚举常量将队列最大长度默认为10
Node* front;//指向头节点的指针
Node* rear;//指向尾节点的指针
int items;//队列中人数
const int qsize;//用户输入队列最大人数
Queue(const Queue & q) : qsize(0){}//伪私有函数,防止类被复制(一旦使用复制构造函数会报错)
Queue &operator=(const Queue &q){return *this;}//伪私有函数,防止类被赋值(一旦使对类用赋值运算符会报错)
public:
Queue(int qs = Q_SIZE);//构造 参数为队列最大人数 默认为10
~Queue();//析构
bool isempty() const;//判断队列是否为空
bool isfull() const;//判断队列是否满员
int queuecount() const;//返回队列中人数的函数
bool enqueue(const Item &item);//增加尾节点的函数
bool dequeue(Item &item);//删除头节点的函数
};
#endif
//queue.cpp
#include<cstdlib>
#include"queue.h"
//构造函数
Queue::Queue(int qs):qsize(qs)// 由于qsize为常量(非静态),应使用成员初始化列表来初始化
{
front = rear = NULL;//初始化为空指针
items = 0;
}
//析构函数 从头部一一删除所有节点
Queue::~Queue()
{
Node * temp;//建立临时指针
while(front != NULL)//在链表不为空前都将执行
{
temp=front;//记录头节点的内存空间地址
front = front->next;//将下一个节点作为新的头节点
delete temp;//释放原头节点的内存空间
}
}
//判断队列是否为空
bool Queue::isempty() const
{
return items == 0;
}
//判断队列是否满员
bool Queue::isfull() const
{
return items == qsize;
}
//返回现有队列中人数
int Queue::queuecount() const
{
return items;
}
//增加尾节点
bool Queue:: enqueue(const Item & item)//参数为新顾客类
{
if(isfull())//先判断队列是否满员 满员则不再增加
return false;
Node* add = new Node;//建立指向新节点的指针 并为新节点分配内存空间
add->item = item;//新节点的成员顾客类被初始化为函数参数的值
add->next = NULL;//新节点的成员指针为空指针
items++;//队列中人数加一
if(front == NULL)//如果加入之前对列为空 则使头指针指向新节点
front = add;
else
rear->next =add;//否则使原尾节点的成员指针指向新节点
rear = add;//并更新尾指针指向新节点
return true;
}
//删除头节点
bool Queue::dequeue(Item & item)
{
if(front == NULL)//先判断队列是否为空 是则返回false
return false;
item = front->item;//记录即将删除的顾客类 (后面有用)
items--;//队列人数减一
//这里与析构函数类似
Node * temp = front;//记录头节点的内存空间地址
front = front->next;//将下一个节点作为新的头节点
delete temp;//释放原头节点的内存空间
if(items == 0)//如果队列此时为空 则尾指针为空
rear = NULL;
return true;
}
//设定顾客信息
void Customer::set(long when){
processtime = std::rand() % 3 + 1;//随机设定顾客受理时间为1~3的某一值
arrive = when;//设定顾客到达时间
}
//bank.cpp
#include <iostream>
#include<cstdlib>
#include<ctime>
#include<ctime>
#include"queue.h"
const int MIN_PER_HR = 60;
bool newcustomer(double x);//判断这一分钟内是否有新顾客
int main()
{
using namespace std;
srand(time(0));
cout<<"Case Study:Bank of Heather Automatic Teller\n";
cout<<"Enter maxinum size of queue: ";
int qs;
cin>>qs;//输入队列允许的最大长度
Queue line(qs);//利用构造函数初始化队列类line
cout<<"Enter the number of simulation hous:";
int hours;
cin>>hours;//输入模拟总时长
long cyclelimit = MIN_PER_HR*hours;//模拟总时长(分钟)
cout<<"Enter the average number of customers per hour:";
double perhour;
cin>>perhour;//输入每小时出现顾客的平均个数
double min_per_cust;
min_per_cust = MIN_PER_HR / perhour;//平均每次顾客到达的时间间隔
Item temp;//新顾客类
long turnaways = 0;//满员时被拒绝的顾客
long customers = 0;//排进队列中的总人数
long served = 0;//已受理的总人数
long sum_line = 0;//累加每分钟的队列人数
int wait_time = 0;//队列中第二位的等待剩余时间
long line_wait = 0;//队列等待总时长
for(int cycle = 0; cycle<cyclelimit; cycle++)//模拟每分钟的过程 一次循环为一分钟
{
//增加新顾客 并设定其信息
if(newcustomer(min_per_cust))//判断这一分钟内是否有新顾客 有则执行循环
{
if(line.isfull())//判断队列是否满员 若满则拒绝人数加一
turnaways++;
else//未满
{
customers++;//进入队列总人数加一
temp.set(cycle);//设定新顾客类到达时间(为当前cycle)和受理时间(1~3的随机数)
line.enqueue(temp);//队列增加尾节点
}
}
//判断atm是否在使用 并及时填补下一位等待顾客开始受理
if(wait_time <= 0 && !line.isempty())//当目前无人受理中 且队列不为空时(若有人受理中则不执行循环)
{
line.dequeue (temp);//删除队列头节点(提前删除准备受理的顾客) 之前保存的头结点信息这里用上了
wait_time = temp.ptime();//将队列中下一位的等待剩余时间 初始化为使用atm顾客的受理时间
line_wait += cycle - temp.when();//队列等待总时长(每位顾客的开始受理时间减到达时间之和)
served++; //受理人数加一
}
//更新等待剩余时间
if(wait_time>0)//当第一位在这一分钟内还在受理
wait_time--;//第二位等待剩余时间少了一分钟(但还在等)
sum_line += line.queuecount();//累加每分钟的队列人数(最后用来算平均每分钟队列人数)
}
//打印结果报告
if(customers > 0)
{
cout<<"customers accepted: "<<customers<<endl;
cout<<" customers served: "<<served<<endl;
cout<<" turnaways: "<<turnaways<<endl;
cout<<"average queue size: ";
cout.precision(2);
cout.setf(ios_base::fixed, ios_base::floatfield);
cout<<(double) sum_line/cyclelimit<<endl;
cout<<" average wait time: "<<(double) line_wait/served<<" minutes\n";
}
else
cout<<"No customers!\n";
cout<<"Done!\n";
return 0;
}
bool newcustomer(double x)//判断这一分钟内是否有新顾客
{
return (std::rand() * x /RAND_MAX < 1);
/*RAND_MAX是整型的最大值为2147483647,rand()返回的是整型,
因此rand()/RAND_MAX返回值要么是0要么是1,但是几乎不为1(概率很小),
例如rand()*6.0/RAND_MAX 的结果为浮点型,这样的结果就会是0.xxx 1.xxx 2.xxx 3.xxx 4.xxx 5.xxx
同理,对于乘以x也是这样,但x必须是一个浮点型,如果x为Int型,那么,
你看到的结果全是0(但也有可能为x,因为rand()的最大值是RAND_MAX,虽然取到的概率很小,但是毕竟有可能取到).
因此小于1的概率为1/x,即x次有一次小于1 */
}
运行结果示例: