ATM 模擬 C++

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是賦值,當qsizeconst

      //區別就出來了,當變量類型是常量(非靜態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;

    // 設置13 的隨機數,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,而whenlong,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

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章