这里我们模拟一下银行排队叫号系统的实现:

假设一个银行有4个窗口对外接待客户。由于每个窗口在某一时刻只能接待一个客户,在客户众多的时候需要排队,对于刚进入银行的客户,如果某个窗口正空闲,
则可上前办理业务,如果所有窗口都不空闲则排在人数最少的窗口。
现在要求模拟银行的某一时间段内的4个窗口的客户排队情况。这里客户到达的时刻和办理业务的时间都是随机的。

首先我们银行发生事件,我们得有一个类表示事件对象

/*
*功能:这个实现的是我们事件的数据单元节点
*文件:Event.h
*时间:2015年7月8日20:55:32
*作者:cutter_point
*/#ifndef EVENT_H
#define EVENT_Hclass Event
{int OccurTime; //事件发生的时刻int NType;     //事件类型,0表示到达事件,1到4表示四个窗口的离开事件
public:Event() //初始化,我们把事件发生的事件和事件类型都首先视为0{this->OccurTime = 0;this->NType = 0;}Event(int Occur, int type){this->OccurTime = Occur;this->NType = type;}//重写=操作符,运算符的重载/*Event& operator=(const Event& event){if (event == NULL){}}*///set和get方法void setOccurTime(int OccurTime) { this->OccurTime = OccurTime; }int getOccurTime() { return this->OccurTime; }void setNType(int type) { this->NType = type; }int getNType() { return this->NType; }};#endif

接着我们用一个链表来存放我们的事件发生链

/*
*功能:这个实现的是链表的功能
*文件:LinkList.h
*时间:2015年7月7日20:33:18,2015年7月8日20:01:31
*作者:cutter_point
*/#ifndef LINKLIST_H
#define LINKLIST_H#include "Event.h"
#include <stdio.h>using namespace std;//链表的一个节点
class Node
{Event event; //创建我们的数据元对象,包含一个事件发生时间和一个事件类型Node* next;
public:Node() { this->next = nullptr; }Node(Event e) { this->event = e; this->next = nullptr; }//set和get方法void setEvent(Event e) { this->event = e; }Event getEvent() { return this->event; }void setNext(Node* n) { this->next = n; }Node* getNext() { return this->next; }
};//我们的链表
class LinkList
{Node* head;    //头指针Node* getTail();   //得到尾部指针
public:LinkList(){ this->head = new Node(); }void insert(Event e);  //给链表末尾添加一个元素Node* pop(); //删除最后一个节点bool listEmpty();   //判断是否是空链表Node* getHead();  //取得头指针
};#endif

实现:

/*
*功能:这个实现的是链表的功能
*文件:LinkList.cpp
*时间:2015年7月7日20:33:18,2015年7月8日20:01:31,2015年7月9日20:42:11
*作者:cutter_point
*/#include "LinkList.h"#include <iostream>using namespace std;/*******************************************************Node****************************************************************************//*******************************************************LinkList****************************************************************************/
//void insert(Event e); //给链表末尾添加一个元素
void LinkList::insert(Event e)
{//插入一个元素,首先我们判断链表中是否含有元素bool a;if (a = this->listEmpty())      //为true就是真this->head = new Node();//现在不管是否含有元素都有一个元素了,但是这个元素时空的,来作为头,接着我们把新的元素添加进去Node *p = this->head;    //用一个游标指针Node* val = new Node(e);//然后把新的val接到元素的末尾p = this->getTail();//现在p指向尾元素,我们把元素接到末尾p->setNext(val); //吧val设为尾部的元素
}//Node* getHead(); //取得头指针
Node* LinkList::getHead()
{return this->head;
}Node* LinkList::getTail()
{Node* p = this->head;while (p->getNext() != nullptr){p = p->getNext(); //循环到最后一个节点}return p;
}//Node* pop(); //删除最后一个节点
Node* LinkList::pop()
{//用一个游标指针Node* p = this->getHead();Node* q = this->getHead();//首先判断是否还有元素可以删除,这个的判断条件就是头指针后面那个是不是为空的if (p->getNext() == nullptr){cout << "事件表为空" << endl;return nullptr;}//循环到最后一个和倒数第二个while (p->getNext() != nullptr){q = p;     //得到上一个节点p = p->getNext();  //去下一个节点}//如果末尾不为空,说明还有元素,那么我们就删除掉最后一个,并返回最后一个q->setNext(nullptr); //吧倒数第二个设定为空,断开连接return p; //返回断开后的那个数据的指针
}//bool listEmpty();    //判断是否是空链表
bool LinkList::listEmpty()
{//判断是否为空的标识就是头指针和尾指针是同一个节点,那么就代表为空if (this->getHead() == this->getTail()){//没有下一个节点return true;}return false; //头结点的下一个不为空
}

然后我们用一个队列对象,来表示银行窗口的队列:

/*
*功能:这个实现的是我们事件的队列
*文件:LinkQueue.h
*时间:2015年7月9日17:17:09
*作者:cutter_point
*/#ifndef LINKQUEUE_H
#define LINKQUEUE_Hclass QNode
{int arrivalTime;   //时间到达时间int duration;   //处理业务所需要的时间QNode* next;    //指向下一个节点
public:QNode(){this->arrivalTime = 0;this->duration = 0;this->next = nullptr;}QNode(QNode* e){this->arrivalTime = e->arrivalTime;this->duration = e->duration;this->next = nullptr;}//set和get方法void setArrivalTime(int arrival) { this->arrivalTime = arrival; }int getArrivalTime() { return this->arrivalTime; }void setDuration(int dur) { this->duration = dur; }int getDuration() { return this->duration; }void setNext(QNode* n) { this->next = n; }QNode* getNext() { return this->next; }
};class LinkQueue
{//QNode* base; //初始化的动态分配存储空间QNode* front; //队列的头QNode* rear;  //队列的尾
public:LinkQueue(); //初始化void enQueue(QNode* e); //插入数据QNode deQueue(); //删除一个数据bool queueEmpty();  //判断队列是否为空QNode getHead();  //获取队列的头元素int length();//set和get方法void setFront(QNode* qn) { this->front = qn; }QNode* getFront() { return this->front; }void setRear(QNode* qn) { this->rear = qn; }QNode* getRear() { return this->rear; }
};#endif

实现:

/*
*功能:这个实现的是我们事件的队列
*文件:LinkQueue.h
*时间:2015年7月9日17:17:09,2015年7月10日15:18:58
*作者:cutter_point
*/#include "LinkQueue.h"//LinkQueue(); //初始化
LinkQueue::LinkQueue()
{//初始化队列的时候,队列是先进先出//首先我们创建一个新的空节点this->rear = this->front = new QNode();this->front->setNext(nullptr);    //初始化的时候只有一个节点,后面的设置为nullptr
}//得到队列的长度
int LinkQueue::length()
{//由于第一个是空的,所以我们判断队列的长度就是尾部和首部的长度int length = 0;QNode* p = this->front; //用一个游标当做指针,指向相应的位置while (p != this->rear){p = p->getNext();++length;}return length;   //返回队列的长度
}//void enQueue(QNode* e); //插入数据
void LinkQueue::enQueue(QNode* e)
{//吧原始e插入到队列中,由于我们的是链表,不用考虑队列会不会满的问题,如果是线性表,我们还要考虑队列是否满的问题,因为初始化的时候,线性表示一次性申请完全的this->rear->setNext(e);//然后重置尾节点this->rear = this->rear->getNext();
}//QNode deQueue(); //删除一个数据,删除的是队首元素
QNode LinkQueue::deQueue()
{//这个就是出队列的动作QNode e;//设置两个游标QNode* p,* q;//我们首先得判断一下是不是只有一个节点,如果是只有一个有效节点,那么就得更新rearif (this->getFront()->getNext() == this->getRear()){this->setRear(this->getFront());    //设置到头结点上}//我们的操作就是把头后面的那个节点拿出来,抛出来p = this->getFront();q = p->getNext();//断裂头和第一个元素的指针,吧指针指向后面一个节点p->setNext(q->getNext());q->setNext(nullptr);//吧q这个节点的值赋值给e然后返回,并回收q的内存e.setArrivalTime(q->getArrivalTime());e.setDuration(q->getDuration());e.setNext(nullptr);delete q;return e;
}//bool queueEmpty();   //判断队列是否为空
bool LinkQueue::queueEmpty()
{//判断是不是为空的理由就是头和尾是不是指向一个地方if (this->getFront() == this->getRear()){return true;}else{return false;}
}//QNode getHead(); //获取队列的第一个元素,这里只是返回第一个元素的拷贝元素
QNode LinkQueue::getHead()
{QNode e;e.setArrivalTime(this->getFront()->getNext()->getArrivalTime());e.setDuration(this->getFront()->getNext()->getDuration());e.setNext(nullptr);return e;
}

我们的主函数:

/*
*功能:假设一个银行有4个窗口对外接待客户。由于每个窗口在某一时刻只能接待一个客户,在客户众多的时候需要排队,对于刚进入银行的客户,如果某个窗口正空闲,
则可上前办理业务,如果所有窗口都不空闲则排在人数最少的窗口。
现在要求模拟银行的某一时间段内的4个窗口的客户排队情况。这里客户到达的时刻和办理业务的时间都是随机的。
**************************************************************************
****这里没有用到线程,其实更好的办法是使用线程,一个线程用来不断产生  ****
****事件(客户的到达),一个线程不断的处理事件,客户的离开,只要银行不 ****
****关门,当事件表为空的时候我们就wait()一个线程,当队列中还有客户的  ****
****时候就吧线程notify,知道银行关门我们就interrupt线程,结束退出     ****
**************************************************************************
*文件:queue.cpp
*时间:2015年7月7日20:33:18,2015年7月8日20:01:31,2015年7月9日20:02:20,2015年7月10日16:45:52,2015年7月12日15:16:41
*作者:cutter_point
*/#include "Event.h"
#include "LinkList.h"
#include "LinkQueue.h"#include <iostream>
#include <ctime>using namespace std;const static int COUNTER = 5;    //一共4个窗口
const static int MAX_TIME = 30;    //这个是最大的事务处理时间
const static int INTERVAL = 5; //每五分钟内出现一个客户LinkList ev;   //事件表
Event en;
LinkQueue* q[COUNTER];      //这个设定为指针数组,数组里面的每个元素是一个指向LinkQueue的指针
QNode customer;
int TotalTime, CustomerNum, closeTime = 50;void open_for_day()
{cout << "************************************************************************" << endl;cout << "*****                         银行开门                             *****" << endl;cout << "*****                         银行开门                             *****" << endl;cout << "************************************************************************" << endl;//初始化所有的数据TotalTime = 0; CustomerNum = 0;en.setOccurTime(0); en.setNType(0);//初始化所有队列for (int i = 1; i < COUNTER; ++i){q[i] = new LinkQueue();}
}//open_for_day()//求得最短的队列
int min_queue(LinkQueue* q[COUNTER])
{int max = 0, usei = 1;for (int i = 1; i < COUNTER; ++i){//循环遍历所有的队列选出最大的那个队列int testmax = q[i]->length();if (testmax > max){max = testmax;usei = i;}}//循环完毕之后max是所有队列中最大的那个return usei;
}void customer_arrived()
{cout << "======================一位客户到达======================" << endl;//处理客户到达事件,en.NType=0QNode *qe = new QNode();  //客户到达时间,处理业务所需要的时间,指向下一个对象int durtime, intertime;    //一个是处理业务所需要的时间,一个是下一个客户到达的所需时间++CustomerNum;  //人数++//参数两个随机数,代表处理业务需要的时间,下一个客户到达的时间durtime = rand() % (MAX_TIME + 1);  //这个额是[0 ~ MAX_TIME(30)]intertime = rand() % (INTERVAL + 1);  //这个是下一个客户进入银行要等待的时间[0~INTERVAL(5)]//如果银行没有关门,我们要产生下一个事件到达int t = en.getOccurTime() + intertime;if (t < closeTime){//插入事件表下一个事件Event ei;ei.setOccurTime(t);ei.setNType(0);ev.insert(ei);}int i = min_queue(q); //求得最短的队列,注意我们有1到4队列,没有0队列//吧事件插入到最短的队列中//首先我们的事件发生时间(事件到达时间)和执行时间qe->setArrivalTime(en.getOccurTime());qe->setDuration(durtime);   //时间的执行时间q[i]->enQueue(qe);  //吧qe插入到链表中//判断我们插入的队列是不是长度是1,如果是代表在插入之前这个窗口是空的,这个的作用//客户离开事件,是要首先计算该客户在银行逗留的时间,然后从队列中删除该客户之后查看队列是否为空,若不为空则设定一个新的对头客户离开事件en.setOccurTime(en.getOccurTime() + durtime);  //设置新的时间到达事件en.setNType(i); //0代表新的客户到达,1是1号窗口客户离开,2是2号窗口客户离开,3是3号窗口客户离开,4是。。。,这里是客户到达事件,所以是0if (q[i]->length() == 1){//吧第i个队列的离开事件插入事件表,等会用来计算窗口的客户总时间ev.insert(en);}}//customer_arrived()//处理客户离开事件,是要首先计算该客户在银行逗留的时间,然后从队列中删除该客户之后查看队列是否为空,若不为空则设定一个新的对头客户离开事件
void customer_departure()
{cout << "======================一位客户离开======================" << endl;//处理客户离开事件,就是Ntype > 0int i = en.getNType(); //得到事件的类型q[i]->deQueue();    //吧排头删除,表示排头客户离开TotalTime += en.getOccurTime() - customer.getArrivalTime();   //这个是客户逗留事件,不包含处理业务的时间,这个计算的也就是客户等待时间//如果走了这个客户,队列不是空,则设定一个新的排头客户if (q[i]->length() != 0){Event e;customer = q[i]->getHead(); //得到排头的客户e.setOccurTime(en.getOccurTime() + customer.getDuration()); //客户开始办理业务时间+客户使用时间,也就是到了客户离开时间e.setNType(i);   //那个窗口的ev.insert(e);}
}//这个函数用来产生一系列事件,我们首先产生20个事件
void create_event()
{for (int i = 1; i < 2; ++i){customer_arrived();}
}void bank_smiulation(int closeTime)
{open_for_day();    //银行开始业务create_event(); //产生事件while (!ev.listEmpty())   //只要事件表还没空{//Node* p = ev.getHead();   //从事件链表中弹出事件Node* p = ev.pop();en = p->getEvent(); //取出时间if (en.getNType() == 0){//客户到达事件customer_arrived();}else{//客户离开customer_departure();}}//while//计算并输出平均逗留时间cout << "平均逗留时间是:" << (float)TotalTime/CustomerNum << endl;
}int main()
{bank_smiulation(closeTime);//ev.getHead()->getEvent().getOccurTime();//cout << "hello world" << ev.getHead()->getEvent().getOccurTime()<<endl;return 0;
}

实现效果:

【数据结构】3、模拟银行窗口排队叫号系统——C++相关推荐

  1. 模拟银行窗口排队叫号系统的运作

    最近在网上看到了一道面试题,初看很简单,细看有点意思的一道题目: http://blog.csdn.net/zhangxiaoxiang/archive/2011/04/01/6294132.aspx ...

  2. 数据结构——数据结构模拟银行排号叫号系统参考

    数据结构模拟银行排号叫号系统参考 4/27.作业三 用队列的简单操作实现,代码较简单,提示信息易懂 定义一个结构体SqQueue 判断队列是否为空 判断队列是否已满 向队列中插入元素 元素e出队,并用 ...

  3. 51单片机银行自助排队叫号系统VIP热敏打印功能DY-SV17F语音播报

    实践制作DIY- GC0138-银行自助排队叫号系统VIP 基于51单片机设计---银行自助排队叫号系统VIP 二.功能介绍: STC89C52最小系统板+0.96寸OLED显示器+DY-SV17F语 ...

  4. 用循环队列模拟银行窗口排队_银行告诉你什么是无锁队列

  5. mfc 子窗体 按钮不触发_资深程序员用c++开发MFC银行排队叫号系统,小白看了也能学会...

    这个C++ 银行排队叫号系统是看了书后写出来的程序,运用于MFC理念编写,我看的书是谭浩强的<C++面向对象程序设计>相对计科的书少了前六章 直接从对象讲起,这本书也是本班使用人数最多的一 ...

  6. 排队叫号 服务器 不同区域显示,银行排队叫号系统,让你摆脱排队久的问题!...

    原标题:银行排队叫号系统,让你摆脱排队久的问题! 银行排队叫号系统主要由服务器.取号机.集中液晶屏.液晶窗口显示通屏.语音系统.线缆连接部件及其他辅件等组成. ① 网络平台:可以是大厅的局域网络,系统 ...

  7. VS+Qt+C++银行排队叫号系统

     程序示例精选 VS+Qt+C++银行排队叫号系统 如需安装运行环境或远程调试,见文章底部个人QQ名片,由专业技术人员远程协助! 前言 这篇博客针对<<VS+Qt+C++银行排队叫号系统& ...

  8. 基于java+ssm+vue+mysql的银行排队叫号系统

    项目介绍 银行排队叫号系统是以科学合理的机构组织合作.流畅疏通的信息渠道为平台,以客户基本信息.计算机.Internet网络.网络管理软件信息技术为手段建立的信息服务管理系统.系统将借助高速和先进的计 ...

  9. 51单片机热敏打印自助排队叫号系统银行医院柜台DY-SV17F语音播报

    实践制作DIY- GC0079-自助排队叫号系统 一.功能说明: 基于51单片机设计-自助排队叫号系统 功能介绍: STC89C52RC最小系统板+0.96寸OLED显示器+DY-SV17F语音串口语 ...

  10. 基于51单片机的双机串口通信排队叫号系统(LCD显示)设计

    基于51单片机的双机串口通信排队叫号系统(LCD显示)设计 1 开发环境 视频讲解 2 功能说明介绍 3 仿真图 4 程序 5 原理图 6 视频讲解 7 设计报告 7.1 设计目的 7.2 设计要求及 ...

最新文章

  1. 看完 50000 张专辑封面后,AI 设计师疯狂输出
  2. C# indexof和indexofany区别(转)
  3. dbca no protocol support
  4. python 编程笔记
  5. 记一次kafka数据丢失问题的排查
  6. css中px、em和rem的区别总结
  7. 使用Laravel Eloquent ORM 时如何查询表中指定的字段
  8. 从崩溃的选课系统,论为什么更安全的 HTTPS 协议没有被全面采用
  9. fastadmin model关联模型 关联查询问题
  10. 排序sort,统计wc
  11. 关于CMS的那点事 I
  12. 【java异常】No enum constant org.apache.ibatis.type.JdbcType.number
  13. 初踩阿里云效代码管理
  14. 深度学习之Bias/Variance偏差、方差
  15. 学计算机没有女朋友绕口令,十句以上绕口令
  16. 读 python 机器学习实践指南
  17. C#/VB.NET 在Excel单元格中应用多种字体格式
  18. Python * ** 打包解包 详解
  19. BMZCTF WEB WEB_penetration
  20. k8s开发基础-架构

热门文章

  1. 筑业软件加密锁驱动_如何在不使用额外软件的情况下对USB驱动器进行加密和密码保护...
  2. 2023考研计算机408王道考研网盘资源
  3. android pickerview 多行,Android PickerView 自定义条件选择器 联动
  4. android pickerview 多行,Android-PickerView系列之介绍与使用篇(一)
  5. linux下的PDF阅读器
  6. php 保存文件并换行,php是怎样向文件中写入换行_后端开发
  7. logisim基础(非常基础)----寄存器元件的使用
  8. 物业费管理java_java毕业设计_springboot框架的物业收费管理系统
  9. JavaWeb-谷歌验证码的使用
  10. 使用ThinkPHP扩展,实现Redis的CURD操作。