您的位置:首页 > 理论基础 > 数据结构算法

项目实战笔记 | C++ 实现银行排队服务模拟1 数据结构设计 |实验楼项目

2018-01-07 18:24 771 查看
2017年12月11日

使用蒙特卡洛方法,

Random.hpp:

//

//  Random.hpp

//  QueueSystem

//

 

#ifndefRandom_hpp

#defineRandom_hpp

//语句1#ifndef
标识1

语句2 #define
标识1

语句3 #endif

语句4 ……

语句5 ……

该段代码意思是:如果标识1没有被定义,则重定义标识1,即执行语句2、语句3;如果标识1已经被定义,则直接跳过语句2、语句3,直接执行语句4、语句5、……

 

#include<cstdlib>//实现了c语言的一些方法

#include<cmath>

 

class Random {

public:

    // [0, 1) 之间的服从均匀分布的随机值

    static double uniform(double max = 1) {

        return ((double)std::rand() /(RAND_MAX))*max;//这一句有一些绕口,include <cstdlib>可以使用std::中的rand()函数,rand函数生成1_rand_max-1的随机数,然后除以rand_max,最后乘以max,可以生成【0,max)的随机数

    }

};

#endif /*Random_hpp */

 

//

// main.cpp

// QueueSystem

//

 

#include"QueueSystem.hpp"

 

#include<iostream>

#include<cstdlib>

 

int main() {

 

    std::srand((unsigned)std::time(0)); // 使用当前时间作为随机数种子

 

    int total_service_time = 240;       // 按分钟计算

    int window_num         = 4;

    int simulate_num       = 100000;    // 模拟次数

 

    QueueSystem system(total_service_time,window_num);

    system.simulate(simulate_num);

    std::cout << "The average timeof customer stay in bank: "

              << system.getAvgStayTime()<< std::endl;

    std::cout << "The number ofcustomer arrive bank per minute: "

              << system.getAvgCustomers()<< std::endl;

 

    return 0;

}

 

来源: 实验楼

链接: https://www.shiyanlou.com/courses/557
本课程内容,由作者授权实验楼发布,未经允许,禁止转载、下载及非法传播

 

//

//  Node.hpp

//  QueueSystem

//

 

#ifndef Node_hpp

#define Node_hpp

 

#include"Random.hpp"

 

#defineRANDOM_PARAMETER 100

 

struct Node {

    int arrive_time;

    int duration;

    struct Node *next;//在结构体内定义结构体指针需要加上 struct前缀

 

// 默认到达事件为0,需要服务的事件是随机的

//类默认是私有的,结构体默认是公有的

    Node(int arrive_time = 0,

         int duration = Random::uniform(RANDOM_PARAMETER)):

        arrive_time(arrive_time),

        duration(duration),

        next(NULL) {}

};

 

typedef structNode Node;

typedef structNode Customer;

 

#endif /* Node_h*/

//endif以后最好加上文件名,以区分该endif是哪个文件的

 

来源: 实验楼

链接: https://www.shiyanlou.com/courses/557
本课程内容,由作者授权实验楼发布,未经允许,禁止转载、下载及非法传播

 

接下来是ServiceWindow的设计

//  ServiceWindow.hpp

//  QueueSystem

//

 

#ifndefServiceWindow_hpp

#defineServiceWindow_hpp

 

#include"Node.hpp"

 

enumWindowStatus {

    SERVICE,

    IDLE,

};

 

classServiceWindow {

public:

inline ServiceWindow() //inline内联函数,要求函数非常的简单,里面没有例如while,switch等复杂的结构控制语句,且不能是直接递归函数,且inline是一个建议的语句,是否内联还要看编译器怎么说,在内联处编译器一定要明白函数的定义才行

{

        window_status = IDLE;

    };

    inline bool isIdle() const {

        if (window_status == IDLE) {

            return true;

        } else {

            return false;

        }

    }

    inline void serveCustomer(Customer&customer) {

        this->customer = customer;

    }

    inline void setBusy() {

        window_status = SERVICE;

    }

    inline void setIdle() {

        window_status = IDLE;

    }

    inline int getCustomerArriveTime() const {

        return customer.arrive_time;

    }

    inline int getCustomerDuration() const {

        return customer.duration;

    }

private:

    Customer customer;

    WindowStatus window_status;//当定义了枚举之后,这里是WindowStatus,则可以将定义的枚举名称当做类名使用,可以直接定义枚举变量,枚举变量可以等于枚举里面的值

};

 

#endif /*ServiceWindow_hpp */

 

来源: 实验楼

链接: https://www.shiyanlou.com/courses/557
本课程内容,由作者授权实验楼发布,未经允许,禁止转载、下载及非法传播

这里虽然编写好了顾客的类和窗口的类,当是现在这个程序还是静态的,并没有动起来,我们还需要考虑更多逻辑的问题

这里使用事件驱动的方法来管理整个系统的时间线

Event.hpp:
 

//

//  Event.hpp

//  QueueSystem

//

 

#ifndefEvent_hpp

#defineEvent_hpp

 

#include"Random.hpp"

#defineRANDOM_PARAMETER 100

 

struct Event {

    int occur_time;

 

    // 使用 -1 表示到达事件, >=0 表示离开事件, 同时数值表示所离开的服务窗口

    int event_type;

 

    Event* next;

 

    // 默认为到达事件,发生事件随机

    Event(int occur_time =Random::uniform(RANDOM_PARAMETER),//一个类的静态方法除了可以使用.来调用以外,还可以使用::方法来调用

          int event_type = -1):

        occur_time(occur_time),

        event_type(event_type),

        next(NULL) {}

};

 

#endif /*Event_hpp */

 

来源: 实验楼

链接: https://www.shiyanlou.com/courses/557
本课程内容,由作者授权实验楼发布,未经允许,禁止转载、下载及非法传播

接下来我们来设计存储顾客和窗口以及事件的队列,顾客和窗口的队列直接从后面插入就好了,而事件的队列必须按照发生的时间顺序插入

//

//  Event.hpp

//  QueueSystem

//

 

#ifndefEvent_hpp

#defineEvent_hpp

 

#include"Random.hpp"

#defineRANDOM_PARAMETER 100

 

struct Event {

    int occur_time;

 

    // 使用 -1 表示到达事件, >=0 表示离开事件, 同时数值表示所离开的服务窗口

    int event_type;

 

    Event* next;

 

    // 默认为到达事件,发生事件随机

    Event(int occur_time =Random::uniform(RANDOM_PARAMETER),

          int event_type = -1):

        occur_time(occur_time),

        event_type(event_type),

        next(NULL) {}

};

 

#endif /*Event_hpp */

 

来源: 实验楼

链接: https://www.shiyanlou.com/courses/557
本课程内容,由作者授权实验楼发布,未经允许,禁止转载、下载及非法传播

这里的顾客,窗口和事件列表使用的都是队列的形式,因此使用队列就好了

//  Queue.hpp

//  QueueSystem

//

 

#ifndefQueue_hpp

#defineQueue_hpp

 

#include<iostream>

#include<cstdlib>

 

#include"Event.hpp"

 

// 带头结点的队列

template<typename T>//这一句和template<class T>的意思是一样的,功能也是一样的

class Queue

{

public:

    Queue();

    ~Queue();

    void clearQueue();             // 清空队列

    T* enqueue(T &node);//适合于任何类型的人队

    T* dequeue();

    T* orderEnqueue(Event &event); // 只适用于事件入队

    int length();

private:

    T *front; // 头结点

    T *rear;  // 队尾

};

#endif /*Queue_hpp */

 

来源: 实验楼

链接: https://www.shiyanlou.com/courses/557
本课程内容,由作者授权实验楼发布,未经允许,禁止转载、下载及非法传播

这样的话,基本结构的设计就完成了,接下来是对基本结构的使用以及逻辑运行,来实现银行排队系统

系统管理类

//

//  QueueSystem.hpp

//  QueueSystem

//

 

#ifndefQueueSystem_hpp

#defineQueueSystem_hpp

 

#include"Event.hpp"

#include"Queue.hpp"

#include "ServiceWindow.hpp"

 

classQueueSystem {

 

public:

    // 初始化队列系统

    QueueSystem(int total_service_time, intwindow_num);

 

    // 销毁

    ~QueueSystem();

 

    // 启动模拟

    void simulate(int simulate_num);

 

    inline double getAvgStayTime() const {

        return avg_stay_time;

    }

    inline double getAvgCustomers() const {

        return avg_customers;

    }

 

private:

    // 让队列系统运行一次

    double run();

 

    // 初始化各种参数

    void init();

 

    // 清空各种参数

    void end();

 

    // 获得空闲窗口索引

    int getIdleServiceWindow();

 

    // 处理顾客到达事件

    void customerArrived();

 

    // 处理顾客离开事件

    void customerDeparture();

 

    // 服务窗口的总数

    int window_num;

 

    // 总的营业时间

    int total_service_time;

 

    // 顾客的逗留总时间

    int customer_stay_time;

 

    // 总顾客数

    inttotal_customer_num;

 

    // 核心成员

    ServiceWindow*  windows;

    Queue<Customer> customer_list;

    Queue<Event>       event_list;

    Event*          current_event;

 

    // 给外部调用的结果

    double avg_customers;

    double avg_stay_time;

 

};

 

 

#endif /*QueueSystem_hpp */

 

来源: 实验楼

链接: https://www.shiyanlou.com/courses/557
本课程内容,由作者授权实验楼发布,未经允许,禁止转载、下载及非法传播

引用是c++的内容,c语言不存在引用,在C语言中要实现引用的功能,使用指针,传递地址

//枚举

#define MON  1

#define TUE   2

#define WED  3

#define THU   4

#define FRI    5

#define SAT   6

#define SUN   7

//等同于

enum DAY

{

      MON=1, TUE, WED, THU, FRI, SAT, SUN

};

Inline必须对于函数定义,对于函数声明,不起作用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐