【C++】Heather银行对顾客排队等待的时间进行估测问题 《C++ Primer Plus》12.7 队列模拟 学习笔记


前言

今天在看C++ Primer Plus的书的第12章,有一个队列模拟题,遂跟着书一起把代码敲了一遍,并记录如下。以供大家参考和我自己复习!


一、题目要求

Heather银行打算在Food Heap超市开设一个自动柜员机(ATM)。Food Heap超市的管理者担心排队等待使用ATM的人流会干扰超市的交通,希望限制排队等待的人数。Heather银行希望对顾客排队等待的时间进行估测。要编写一个程序来模拟这种情况,让超市的管理者可以了解 ATM可能造成的影响。
队列中的项目是顾客.Heather银行的代表介绍:通常,三分之一的顾客只需要一分钟便可获得服务,三分之一的顾客需要两分钟,另外三分之一的顾客需要三分钟.另外,顾客到达的时间是随机的,但每个小时使用自动柜员机的顾客数量相当稳定.工程的另外两项任务是:设计一个表示顾客的类;编写一个程序来模拟顾客和队列之间的交互

二、解决思路

1.Queue类

在这里插入图片描述
对于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。

2.Customer类

公有接口

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之间的随机整数

3.ATM模拟

是否来了一个新的客户

bool newcustomer(double x) {
	return (std::rand() * x / RAND_MAX < 1);   //产生一个[0,x]的随机数
}

rand()会产生一个0-0xffff即0-32767之间的随机数,RAND_MAX=0X7fffff=32767,故rand()/RAND_MAX 会产生一个[0,1]区间的随机数

害好像代码有点好理解的我还有很多注释,就不解释了,直接放代码叭,如果大家有问题就评论留言就好!

4.完整代码

queue.h

#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_


queue.cpp

#include "queue.h"
#include <cstdlib>

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;
}

bank.cpp

/*   小唐 2023/1/1
 模拟ATM程序: 
	用户需输入
  1.限制排队等待的最大人数
  2.程序模拟的持续时间(小时)
  3.平均每小时客户数
*/

#include <iostream>
#include <cstdlib>
#include <ctime>
#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]的随机数
}

5.结果展示

在这里插入图片描述


总结

最后完结撒花~虽然这个程序比较简单,但是我在敲的时候还是遇到了不少细节问题,唐怡佳继续努力叭!我也会把完整工程文件上传资源,有需要的小伙伴可以自取哦!

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小唐YiJiaTang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值