今天在看C++ Primer Plus的书的第12章,有一个队列模拟题,遂跟着书一起把代码敲了一遍,并记录如下。以供大家参考和我自己复习!
Heather银行打算在Food Heap超市开设一个自动柜员机(ATM)。Food Heap超市的管理者担心排队等待使用ATM的人流会干扰超市的交通,希望限制排队等待的人数。Heather银行希望对顾客排队等待的时间进行估测。要编写一个程序来模拟这种情况,让超市的管理者可以了解 ATM可能造成的影响。
队列中的项目是顾客.Heather银行的代表介绍:通常,三分之一的顾客只需要一分钟便可获得服务,三分之一的顾客需要两分钟,另外三分之一的顾客需要三分钟.另外,顾客到达的时间是随机的,但每个小时使用自动柜员机的顾客数量相当稳定.工程的另外两项任务是:设计一个表示顾客的类;编写一个程序来模拟顾客和队列之间的交互
对于Queue类,经过分析,我们采用链表来满足对列要求,因为队列是先进先出的FIFO,所以我们使用了Node结点struct Node {Item& item; struct Node *next};
这样在对列进出时非常方便,不熟悉的同学可以去看一下链表。
class Queue
{
public:
//接口
Queue(int qs = Q_SIZE); //默认队列可储存10个项目
~Queue();
bool isempyt() const;
bool isfull() const;
int queuecount() const;
bool enqueue(const Item &item); //add
bool dequeue(Item& item);//remove
private:
enum { Q_SIZE = 10 };
struct Node
{
Item item;
struct Node* next; //指向下一个结点
};
Node* front;
Node* rear;
int items;
const int qsize;
//复制构造函数
Queue(const Queue& q) : qsize(0) { }
//运算符重载
Queue& operator=(const Queue& q) { return *this; }
};
注:bool isempyt() const; bool isfull() const; int queuecount() const;
加const是为了保护数据,只读不改变数据。
其中我们把复制构造函数和运算符重载放在了private
中有两个作用:1.它避免了本来自动默认生成的方法定义2.因为这些方法是私有的,所以不能被广泛使用。(其实这里小唐也不太理解,但是书上是这样说的,并且我放在public
中好像确实有点吧小问题,有知道的兄弟们可以教教我!)。反正就是为了避免程序崩溃。
Queue::Queue(int qs) : qsize(qs) {
front = rear = nullptr;
items = 0;
}
Queue::~Queue() {
Node* temp;
while (front != nullptr) {
temp = front;
front= front -> next;
delete temp;
}
}
bool Queue::isempyt() const {
return 0 == items;
}
bool Queue::isfull() const {
return qsize == items;
}
bool Queue::enqueue(const Item& item) {
if (isfull()) {
return false;
}
Node* add = new Node;
add->item = item;
add->next = nullptr;
items++;
if (front == nullptr) {
front = add;
}
else
{
rear->next = add;
}
rear = add;
return true;
}
bool Queue::dequeue(Item& item) {
if (front == nullptr) {
return false;
}
item = front->item;
items--;
Node* temp = front;
front = front->next;
delete temp;
if (0 == items) {
rear = nullptr;
}
return true;
}
int Queue::queuecount() const {
return items;
}
代码大多比较好理解,我就只解释一下我写的时候一开始有点迷糊的地方叭,顺便给自己再复习一遍!
Queue::~Queue() {
Node* temp;
while (front != nullptr) {
temp = front;
front= front -> next;
delete temp;
}
}
虽然在类构造函数中我们没有使用new
,但是我们向队列中添加对象会调用new
来创建新的节点,所以我们需要一个显式析构函数,它从表头开始删除节点,也就是我们先前提到的先进先出FIFO。
class Customer
{
public:
Customer() { arrive = processtime = 0; }
void set(long when);
long when() const { return arrive; }
int ptime() const { return processtime; }
private:
long arrive; //到达时间
int processtime;
};
Customer中有两个私有成员 顾客到达时间 和 顾客处理时间,默认构造函数将创建一个空客户,set()成员函数为arrive和processtime设置参数,processtime根据题目将被设置成一个1-3分钟的随机值。
void Customer::set(long when) {
processtime = std::rand() % (3-1+1) + 1; //处理时间设置为1-3中的任意一个
arrive = when;
}
这里介绍一下随机数是怎么产生的:std::rand() % (b-a+1)+a
表示产生一个a-b之间的随机整数
是否来了一个新的客户
bool newcustomer(double x) {
return (std::rand() * x / RAND_MAX < 1); //产生一个[0,x]的随机数
}
rand()
会产生一个0-0xfff
f即0-32767
之间的随机数,RAND_MAX=0X7fffff=32767
,故rand()/RAND_MAX
会产生一个[0,1]区间的随机数
害好像代码有点好理解的我还有很多注释,就不解释了,直接放代码叭,如果大家有问题就评论留言就好!
#ifndef QUEUE_H_
#define QUEUE_H_
class Customer
{
public:
Customer() { arrive = processtime = 0; }
void set(long when);
long when() const { return arrive; }
int ptime() const { return processtime; }
private:
long arrive; //到达时间
int processtime;
};
typedef Customer Item;
class Queue
{
public:
//接口
Queue(int qs = Q_SIZE); //默认队列可储存10个项目
~Queue();
bool isempyt() const;
bool isfull() const;
int queuecount() const;
bool enqueue(const Item &item); //add
bool dequeue(Item& item);//remove
private:
enum { Q_SIZE = 10 };
struct Node
{
Item item;
struct Node* next; //指向下一个结点
};
Node* front;
Node* rear;
int items;
const int qsize;
//复制构造函数
Queue(const Queue& q) : qsize(0) { }
//运算符重载
Queue& operator=(const Queue& q) { return *this; }
};
#endif // !QUEUE_H_
#include "queue.h"
#include
void Customer::set(long when) {
processtime = std::rand() % (3-1+1) + 1; //处理时间设置为1-3中的任意一个
arrive = when;
}
Queue::Queue(int qs) : qsize(qs) {
front = rear = nullptr;
items = 0;
}
Queue::~Queue() {
Node* temp;
while (front != nullptr) {
temp = front;
front= front -> next;
delete temp;
}
}
bool Queue::isempyt() const {
return 0 == items;
}
bool Queue::isfull() const {
return qsize == items;
}
bool Queue::enqueue(const Item& item) {
if (isfull()) {
return false;
}
Node* add = new Node;
add->item = item;
add->next = nullptr;
items++;
if (front == nullptr) {
front = add;
}
else
{
rear->next = add;
}
rear = add;
return true;
}
bool Queue::dequeue(Item& item) {
if (front == nullptr) {
return false;
}
item = front->item;
items--;
Node* temp = front;
front = front->next;
delete temp;
if (0 == items) {
rear = nullptr;
}
return true;
}
int Queue::queuecount() const {
return items;
}
/* 小唐 2023/1/1
模拟ATM程序:
用户需输入
1.限制排队等待的最大人数
2.程序模拟的持续时间(小时)
3.平均每小时客户数
*/
#include
#include
#include
#include "queue.h"
const int MIN_PER_HR = 60;// 60min/hour
bool newcustomer(double x); //是否接收新客户
int main() {
using std::cin;
using std::cout;
using std::endl;
using std::ios_base;
std::srand((unsigned int)std::time(0)); //种下一个随机种子
cout << "Bank of Heather Automatic Teller\n";
cout << "--------------------------------\n";
cout << "输入限制的排队等待的最大人数: ";
int qs;
cin >> qs;
Queue line(qs);
cout << "输入模拟运行时间: ";
int hours;
cin >> hours;
long cyclelimit = hours * MIN_PER_HR;
cout << "输入平均每小时客户数: ";
double perhour;
cin >> perhour;
double min_per_cust;
min_per_cust = MIN_PER_HR / perhour;
Item temp;
long turnaway = 0;
long customers = 0;
long served = 0;
long sum_line = 0;
long wait_time = 0;
long line_wait = 0;
for (int cycle = 0; cycle < cyclelimit; cycle++) {
if (newcustomer(min_per_cust))
{
if (line.isfull()) //队满了拜拜了您
turnaway++;
else {
customers++;
temp.set(cycle); //随机设置一个处理时间[1,3]min
line.enqueue(temp); //排队去叭您
}
}
if ((wait_time <= 0) && (!line.isempyt())) {
line.dequeue(temp); //处理完了可以滚蛋了
wait_time = temp.ptime();
line_wait += cycle - temp.when();
served++;
}
if (wait_time > 0)
wait_time--;
sum_line += line.queuecount();
}
if (customers > 0) {
cout << "接收的客户数: " << customers << endl;
cout << "服务的客户数: " << served << endl;
cout << "人满潇洒转身离开的客户数: " << turnaway << endl;
cout << "队伍平均数:";
cout.precision(2);
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << (double)sum_line / cyclelimit << endl;
cout << "平均等待时间: " << (double)line_wait / served << "分钟" << endl;
}
else
cout << "没人来!服了!" << endl;
return 0;
}
bool newcustomer(double x) {
return (std::rand() * x / RAND_MAX < 1); //产生一个[0,x]的随机数
}
最后完结撒花~虽然这个程序比较简单,但是我在敲的时候还是遇到了不少细节问题,唐怡佳继续努力叭!
我也会把完整工程文件上传资源,有需要的小伙伴可以自取哦!