类和动态内存分配(3)

这个程序模拟了银行ATM机的排队过程,包括顾客到达、等待时间、办理时间和队列长度的计算。使用了队列数据结构,通过Customer类表示顾客,并提供了enqueue和dequeue操作。在main函数中,模拟了随机生成顾客并根据设定的参数进行服务的过程,最终报告了顾客接受、服务、放弃和平均等待时间等关键信息。

ATM模拟

// queue.h

#pragma once

#ifndef _QUEUE_H_
#define _QUEUE_H_

class Customer
{
private:
	long arrive;
	int processtime;
public:
	Customer()
	{
		arrive = processtime = 0;
	}
	void set(long when);
	long when() const
	{
		return arrive;
	}
	int ptime()const
	{
		return processtime;
	}
};

typedef Customer Item;    //   Customer与Item等价

class Queue
{
private:
	struct Node
	{
		Item item; //顾客数据
		Node* next; //创建指向结构体的指针来形成链表
	};
	enum{Q_size=10};  // 等价于 const static Q_size = 10;
	Node* front;
	Node* rear;
	int items;
	const int qsize; //  const对象 -- 通过成员初始化来赋值/创建的时候直接初始化 (不可以在构造函数中赋值)
	// 将复制构造函数和重载赋值运算符放在private空间中,因为该程序不会用到这两个功能,但又要防止意外用到这两个功能遭成不必要的错误
	Queue(const Queue& q) :qsize(0) { };
	Queue& operator=(const Queue& q) { return *this; };
public:
	Queue(int qs = Q_size);
	~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"



// class: Queue
Queue::Queue(int qs) :qsize(qs)  //将qs赋值给const对象qsize -- 成员初始化
{
	front = rear = NULL; // nullptr,(void *)0 均可
	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; // 向后添加,最后一位的后面为NULL
	items++;
	if (front == NULL) //如果是第一个
	{
		front = add;
	}
	else
	{
		rear->next = add;  //当前最后一位的下一位为add,即新添加的成员
	}
	rear = add;  //将rear标记至最后一位,方便后续的添加
	return true;
}

bool Queue::dequeue(Item& item)  // dequeue的主要逻辑为: 用一个临时指针保存front的地址,再更新front值front->next即下一位,最后再delete临时指针指向的那块内存即可完成dequeue
{
	if (front == NULL)
	{
		return false;
	}
	item = front->item; //参数的作用为获取被dequeue的成员的信息
	items--;	
	Node* temp = front;
	front = front->next;
	delete temp;
	if (items == 0)
	{
		rear = NULL;
	}
	return true;
}


// class Customer
void Customer::set(long when)
{
	processtime = std::rand() % 3 + 1;
	arrive = when;
}

// bank.cpp

#include<iostream>
#include<cstdlib>    // RAND_MAX 和 RAND_MIN 分别为rand()可以返回的最大值和最小值
#include<ctime>
#include"queue.h"
const int MIN_PER_HR = 60;
using namespace std;

bool newcustomer(double x);

int main()
{
	srand(time(0));

	//队列允许同时存在的最大人数设置
	cout << "Case Study: Bank of Heather Automatic Teller" << endl;
	cout << "Enter maximum size of queue";
	int qs;
	cin >> qs;
	Queue line(qs);

	//总共的模拟时间设置
	cout << "Enter the number of simulations hours: ";
	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++)   // cycle用于标记位置
	{
		if (newcustomer(min_per_cust)) //如果有新顾客
		{
			if (line.isfull()) //如果当前队列已满
			{
				turnaways++; 
			}
			else //且队列并不满
			{
				//进行enqueue过程
				customers++;
				temp.set(cycle); //set的作用为设置当前顾客是第几分钟到达的且通过rand随机数来设置该顾客所需要的processtime
				line.enqueue(temp);
			}
		}
		if (wait_time <= 0 && !line.isempty()) //如果等待时间小于0且队列并不空
		{
			//进行dequeue过程 (被dequeue的那个对象被送去办理,应当保存其processtime -- wait_time)
			line.dequeue(temp);   //确认将要dequeue的对象为temp,则temp被送去进行办理
			wait_time = temp.ptime(); //同时temp办理所需要的时间保存至wait_time
			line_wait += cycle - temp.when();  //所处的队列位置为当前的位置减去顾客进入时的位置
			served++;
		}
		if (wait_time > 0)  //当wait_time仍大于0时,说明temp仍在办理,wait_time--
		{
			wait_time--;
		}
		sum_line += line.queuecount();
	}

	//reporting:
	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" << endl;
	}
	else
	{
		cout << "No customers!" << endl;
	}
	cout << "Done!" << endl;

	system("pause");
	return 0;
}

bool newcustomer(double x)
{
	return (rand() * x / RAND_MAX < 1);
}

知识点

1.成员初始化:用于const和引用成员  -- 只可在创建时进行初始化的成员

2.成员初始化语法:即在实现文件中的构造函数定义上进行更改(在参数的右边加上冒号,且赋给多个值时应当用逗号隔开)

eg:

Queue::Queue(int qs) : mem1(val1),mem2(val2)
{
   
}

3. 若程序无需用到成员自定义的复制构造函数和重载后的赋值运算符,可以将这两个对象函数定义在private空间中,防止意外用到这两个功能而造成不必要的麻烦(此时若调用这两个函数,IDE将会报错)  -- 称作伪私有法

eg:

class Queue
{
private:
	// 将复制构造函数和重载赋值运算符放在private空间中,因为该程序不会用到这两个功能,但又要防止意外用到这两个功能遭成不必要的错误
	Queue(const Queue& q) :qsize(0) { };
	Queue& operator=(const Queue& q) { return *this; };
};

4. RAND_MAX 和 RAND_MIN 分别为rand()可以返回的最大值和最小值,所以有0<= rand() / RAND_MAX <=1  

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值