ATM 模擬來自C++ Primer Plus
Queue.h
#ifndef QUEUE_H
#define QUEUE_H
#include<iostream>
//模板函數、模板類
//新發現,單獨的模板函數不能分.h.cpp
template<class T>
class FQueue
{
private:
struct Node
{
T item;
struct Node* next;
};
// T& a = item;//ok
// 引用可以內部,外部列表初始化
// T& a; //無意義,試引用列表初始化
// static const int qshi;//無意義,只爲測試類外初始化static模板類時
enum {Qsize = 10};//10後面無分號
Node * front; //首元素
Node * rear; //尾元素
int items;
const int qsize;
//這是一個編程技巧,下面定義僞私有方法,爲保證不小心調用=等,程序不會崩潰 PlusP468
FQueue(const FQueue & q):qsize(0){}
FQueue& operator =(const FQueue & q) {return this;}
//定義了這兩個方法後,若再在類外不小心調用了隊列的對象a = b則會報錯
//eg: FQueue snick(nip);tuck = nip;都會編譯出錯,另外還要注意
//返回值是要返回引用,否則也將隱蔽的調用複製構造函數,所以用類對象時不要輕易返回對象主返回引用
public:
FQueue(int qs);
~FQueue();
bool isempty() const;
bool isfull() const;
int queuecount() const;
bool enqueue(const T &item);
bool dequeue(T& item); //這裏本來不用傳參,只是這裏返回了T/F,所以用引用的方式返回值
};
//template<class T > const int FQueue<T>::qshi = 10;
//這裏又一個知識點,static 有總結,C++11標準單獨const可以類內初始化,單獨static不可以
//二者連起來也可以,但是這裏的點是類外初始化時的格式,注意無static關鍵字
// 如果不是模板類則const int FQueue::qsize = 10
template<class T>
//FQueue<T>::FQueue(int qs):qsize(qs),qshi(10)
//多個時用逗號相隔,另外驗證這種初始化不能用於靜態常量
//FQueue<T>::FQueue(int qs):qsize(qs),a(items) //試試引用列表初始化
FQueue<T>::FQueue(int qs):qsize(qs)
//這裏又一個知識點,:qsize(qs)是初始化,qsize = qs是賦值,當qsize是const時
//區別就出來了,當變量類型是常量(非靜態const)或引用時,必須採用這種初始化方法 Primer Plus P464
//有點出入,因爲C++11已經支持非靜態const類內初始化,所以也不是必須
{
front = nullptr;
rear = nullptr;
items = 0;
//qsize = qs;//給參數提供默認值
}
template<class T>
FQueue<T>::~FQueue() //class名字後面別忘了加<T>
{
//保證對象消亡時,依次刪除各個節點(因爲是new產生)
//這是一種很好的刪除方式
Node * temp;
while(nullptr != front)
{
temp = front;
front = front->next;
delete temp;
}
}
template<class T>
bool FQueue<T>::isempty() const
{
return 0 == items; //高效,別if了,總忘
}
template<class T>
bool FQueue<T>::isfull() const
{
return items == qsize;
}
template<class T>
int FQueue<T>::queuecount() const
{
return items;
}
template<class T>
bool FQueue<T>::enqueue(const T &item)
{
if (isfull())
return false;
Node * add = new Node;
add->item = item;
add->next = nullptr;
items++;
if (nullptr == front) //測試時崩潰了,又是因爲這種==寫成了=
front = add;
else
rear->next = add;
rear = add;
return true;
}
template<class T>
bool FQueue<T>::dequeue(T& item)
{
if (nullptr == front)
return false;
item = front->item;
Node * temp = front; //這裏多這一步是爲了刪除已經出隊列的節點
front = front->next;
delete temp; //爲節省內存,刪除已經出列的節點,這是以前自己寫一直想做的,不只是指示變量移位,也達到了真正刪除
items--;
if (0 == items)
rear = nullptr;
return true;
}
#endif // QUEUE_H
Customer.h
#ifndef CUSTOMER_H
#define CUSTOMER_H
#include<cstdlib> //rand in it
class Customer
{
private:
long arrive; //arrival time for customer
int processtime;// processing time for customer
public:
Customer(){arrive = processtime = 0;}
void set(long when);
long when() const {return arrive;}
int ptime() const{return processtime;}
};
void Customer::set(long when)
{
processtime = std::rand() % 3 + 1;
// 設置1到3 的隨機數,Plus P461介紹的,顧客獲得服務的時間爲1~3分鐘
arrive = when;
}
#endif // CUSTOMER_H
Main.cpp
#include <iostream>
#include<cstdlib> //for rand and srand
#include<ctime> // for time
#include"queue.h"
#include"customer.h"
bool newcustomer(double x); //if there is a new customer
const int MIN_PER_HR = 60;
//試繼承類public下,基類的私有成員成爲派生類的一部分,但只能通過基類的公有和保護方法訪問
//class shiji : public Customer
//{
// public:
// void show(){std::cout << arrive ;} //錯誤
//};
int main()
{
using namespace std;
srand(time(0)); //random initializing of rand()
cout << "Case Study: Bank of Fan Automatic Teller" << endl;
cout << "Please enter maximum size of queue: ";
int qs;
//檢查輸入
while (!( cin >> qs) )
{
cout << endl << "Bad input! Please input again : " ;
cin.clear();
cin.ignore(256,'\n');// 爲什麼要Ignore,因爲cin雖然可以自動忽略空格回車符等
//但是若輸入不成功,字符被放回輸入流
// cin.get(); //單個錯誤字符輸入也可用這個處理掉,但是若輸入多個字符則
//判斷違法輸入也可終止程序,需cstdlib,然後退出是exit(EXIT_FAILURE);
//()內是給系統發出的信號,EXIT_DAILURE宏定義爲1
}
FQueue<Customer> line(qs);
cout << "Please input the number of simulation hours : ";
int hours;
cin >> hours; //上面已經演示如何檢查輸入了,這裏爲了簡潔就不再了
long cyclelimit = MIN_PER_HR * hours;
cout << "Please input the average number of customer per hour :";
double perhour;
cin >> perhour;
double min_per_cust;
min_per_cust = MIN_PER_HR / perhour;
Customer temp; //new customer data
long turnaways = 0; //turned away(拒絕) by full queue
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)) //have newcomer
{
if(line.isfull())
turnaways++;
else
{
customers++;
temp.set(cycle); //cycle = time of arrival(這裏是Int,而when是long,這long是不是多佔空間了)
line.enqueue(temp);
}
}
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();
//隊列長度
}
//show results
if (customers > 0)
{
cout << "customers accepted : " << customers << endl;
cout << " customers serverd :" << served << endl;
cout << " turnaways: " << turnaways << endl;
cout << "average queue size:";
cout.precision(2); //控制精度,定點模式fixed和科學技術下,精度指小數點後尾數,默認指總位數
cout.setf(ios_base::fixed,ios_base::floatfield); //控制輸出格式第一第二參數的形式Plus P749
cout << (double)sum_line /cyclelimit <<endl;
cout << " average wait time: " << (double) line_wait/served << " minutes" << endl;
}
else
cout << "No customers!" << endl;
cout << " bye!" << endl;
cin.clear(); //清楚標誌位
while (cin.get() != '\n')
continue; //清楚輸入流數據
return 0;
}
bool newcustomer(double x)
{
return (std::rand()*x/RAND_MAX < 1);
}
//定義依次循環一分鐘,這裏平均六分鐘來一個客戶,所以一分鐘來客戶的概率是1/6
//rand/RAND_MAX 返回0~1 ,乘以x,就是返回0~x,這裏返回0~6,<1的概率1/6