1.總客戶數
2.客戶總逗留時間
3.客戶平均逗留時間
問題分析

銀行類:
銀行類的方法:

隊列:

有序鏈表:

void Bank::Simulation()算法:
1.開門營業,OpenForDay()
2.如果有事件發生,那么:
(1) 對於到達事件,處理到達事件,CustomerArrived(Event *event)
(2) 對於離開事件,處理離開事件,CustomerDeparture(Event *event)
3.重復第2步
4.輸出統計結果
void Bank::OpenForDay()算法:
1.初始化_queue_number為某個正整數
2.初始化_close_time為以秒為單位的時間,比如8*3600,表示8個小時
3.初始化_total_time為0
4.初始化_customer_number為0
5.設定第一個客戶到達事件,客戶到達時刻為0
6.隊列和有序鏈表的初始化(這是由C++STL類自己完成的)
void CustomerArrived(Event *event)算法:
1.產生隨機數:客戶辦理業務需要的時間,假設一個客戶最多需要30分鍾
2.產生隨機數:下一個客戶到達的時間間隔,假設最多10分鍾來一個客戶
3.下一個客戶到達時刻是當前事件發生時刻和時間間隔的和
4.如果到達時刻銀行沒有下班,產生一個新的客戶到達事件插入事件有序鏈表
5.給鏈表按事件的發生時刻排序(因為STL中沒有有序鏈表)
6.找一個最短的隊列
7.在最短的隊列中插入新到的客戶
8.如果隊列中有且只有一個客戶,生成該客戶的一個離開事件插入到事件表
這種情況下,離開事件發生時刻=到達時刻+辦理業務需要的時間
9.統計客戶數量
void CustomerDeparture(Event *event)算法:
1.計算該客戶在銀行中的逗留時間,並且累加總逗留時間
客戶在銀行中的逗留時間=客戶離開事件發生時刻-客戶到達時刻
2.從隊列中刪除該客戶
3.如果隊列不空則設定一個新的隊頭客戶離開事件
隊頭離開事件發生時刻=上個離開事件發生時刻(隊頭開始辦業務的時刻)+隊頭辦業務需要時間
[capture list](parameter list)->return type {function body}
[capture list](parameter list)->return type {function body}
舉例:
_event_list.sort(
[](const Event &e1, const Event &e2) -> bool
{return e1._occur_time < e2._occur_time;});
定義頭文件
#ifndef __BANK_H__
#define __BANK_H__
// #include<其它頭文件>
// const、constexpr and class 定義
// extern 多文件共享變量聲明
#endif
<------以下為實現代碼------>

#include "stdafx.h" #include "bank.h" #include <iostream> #include <clocale> #include <chrono> #include <cstdlib> /* #include <algorithm> std::sort(_work_queue, _work_queue + _queue_number, [](const std::queue<QueueNode> &q1, const std::queue<QueueNode> &q2) -> bool {return q1.size() < q2.size();}); */ Bank::Bank(int window, int close_time) :_queue_number(window), _close_time(close_time), _total_time(0), _customer_number(0) { _work_queue = new std::queue<QueueNode>[window]; srand(std::chrono::system_clock ::to_time_t(std::chrono::system_clock::now())); } Bank::~Bank() { delete[] _work_queue; } void Bank::OpenForDay() { // 第一個客戶到達 _event_list.push_back({0, 0}); } // 客戶到達事件 // 客戶到達時,有三件事需要做: // 1:為此時刻到達的客戶隨機產生一個辦理事務需要時間 // 2:隨機產生下一客戶到達的時間間隔 // 3:把到達的客戶放入一個最短的工作隊列 void Bank::CustomerArrived(Event *event) { ++_customer_number; int duration_time, inter_time; // 此時刻到達客戶辦理事務需要時間 duration_time = rand() % 1800 + 1; //一個客戶最多要30分鍾 // 下一個客戶在從event->_occur_time+inter_time時刻到來 inter_time = rand() % 600 + 1; // 最多10分鍾來一個客戶 // 下一個客戶到達時間 int t = event->_occur_time + inter_time; // 銀行還沒有關門 if(t < _close_time) { _event_list.push_back({t, 0}); // 按到達時間排序事件表,早前晚后 SortEventList(); } // 選一個最短隊列排隊 int i; i = FindShortestQueue(); _work_queue[i].push({event->_occur_time, duration_time}); if(_work_queue[i].size() == 1) { // 這個i隊列第一個客戶,生成他的離開事件 _event_list.push_back( {event->_occur_time + duration_time, i + 1}); SortEventList(); } } void Bank::CustomerDeparture(Event *event) { int i = event->_type - 1; QueueNode customer; // 客戶事務處理完畢,離開 customer = _work_queue[i].front(); _work_queue[i].pop(); _total_time += event->_occur_time - customer._arrival_time; // 第i個隊列的一個離開事件 if(!_work_queue[i].empty()) { customer = _work_queue[i].front(); _event_list.push_back( {customer._duration_time + event->_occur_time, i + 1}); SortEventList(); } } int Bank::FindShortestQueue() { int result = 0; for(int i = 0; i < _queue_number; ++i) { if(_work_queue[result].size() > _work_queue[i].size()) result = i; } return result; } void Bank::SortEventList() { // 方法一,Lambda表達式: _event_list.sort( [](const Event &e1, const Event &e2) -> bool {return e1._occur_time < e2._occur_time;}); // 方法二: // 你知道怎么寫一個函數來比較兩個event嗎? // 其實就是把Lambda表達式寫成一個函數,把 // 這個函數作為sort的參數就可以了。 // 方法三,使用 struct Event::operator< : _event_list.sort(); // 注意:上面的方法一和方法二可以注釋掉任何一個, // 寫兩個,只是為了演示。 } void Bank::Simulation() { OpenForDay(); Event event; while(!_event_list.empty()) { event = _event_list.front(); _event_list.pop_front(); if(event._type == 0) // 到達事件 CustomerArrived(&event); else CustomerDeparture(&event); } // 計算並輸出平均逗留時間 std::wcout << L"客戶數:" << _customer_number << std::endl << L"總逗留時間(小時):" << (double)_total_time / 3600.0 << std::endl << L"平均逗留時間(分鍾):" << (double)_total_time / (double)(_customer_number * 60) << std::endl; } int wmain(int argc, wchar_t *argv[], wchar_t *env[]) { _wsetlocale(LC_ALL, L""); Bank bank; bank.Simulation(); return 0; }
stdafx.cpp
// stdafx.cpp : source file that includes just the standard includes // bank.pch will be the pre-compiled header // stdafx.obj will contain the pre-compiled type information #include "stdafx.h" // TODO: reference any additional headers you need in STDAFX.H // and not in this file
頭文件:
bank.h
#ifndef __BANK_H__ #define __BANK_H__ #include <queue> #include <list> struct Event { int _occur_time; // 事件發生的時刻 int _type; // 事件類型,0表示到達事件,1到 // 4 表示四個窗口的離開事件 bool operator<(const Event &rhs) { return _occur_time < rhs._occur_time; } }; struct QueueNode { int _arrival_time; // 客戶到達時間 int _duration_time;// 客戶需要的服務員時間 }; class Bank { public: explicit Bank(int window_number = 4, int close_time = 8 * 3600); ~Bank(); void Simulation(); private: int _queue_number; // 隊列個數 int _close_time; // 關門時間 int _total_time; // 累計客戶逗留時間 int _customer_number; // 客戶總數 std::list<Event> _event_list; // 事件鏈表 std::queue<QueueNode> *_work_queue;// 工作隊列 void OpenForDay(); void CustomerArrived(Event *event); void CustomerDeparture(Event *event); int FindShortestQueue(); void SortEventList(); }; #endif
stdafx.h
// stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, but // are changed infrequently // #pragma once #include "targetver.h" #include <stdio.h> #include <tchar.h> // TODO: reference additional headers your program requires here
targetver.h
#pragma once // Including SDKDDKVer.h defines the highest available Windows platform. // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. #include <SDKDDKVer.h>
運行結果: