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

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

被折叠的 条评论
为什么被折叠?



