练习:模拟atm机的等待队列

这篇博客介绍了一个模拟ATM机等待队列的代码实现,通过代码展示了如何处理用户在ATM机前的排队服务流程。运行结果显示了该模拟系统的运作情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

代码如下:

//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 */ 
 } 

运行结果示例:在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值