#include <iostream>
using namespace std;
//定义银行客户,Client作为队列的data域
typedef struct client {
int arrivalTime;//客户到达的时间
int duration;//客户办理业务时间
}Client;
//定义节点类型
template <class DataType>
struct Node {
DataType data;
struct Node* next;
};
//定义队列类
template <class DataType>
class LinkQueue {
private:
Node<DataType>* front, * rear;
int length;
public:
LinkQueue();//建立头结点,初始化属性
~LinkQueue();//释放队列空间
void enQueue(DataType x);//入队;
bool deQueue(DataType& item);//出队,item保存数据
bool getFront(DataType& item);//获取队头元素到item所指单元
bool isEmpty();//判断队列是否为空
void clearQueue();//清空队列
void displayQueue();//显示队列内容
int queueLength();//获取队列元素个数
};
template <class DataType>
LinkQueue<DataType>::LinkQueue() {//有头节点方便
front = new Node<DataType>;//创建一个节点,将节点的地址赋给front
front->next = NULL;
rear = front;
this->length = 0;
}
template <class DataType>
LinkQueue<DataType>::~LinkQueue() {//销毁队列
while (front) {
Node<DataType>* p = front;
front = front->next;
delete p;
}
}
template <class DataType>
void LinkQueue<DataType>::enQueue(DataType x) {//链式队列无需考虑满的问题,返回void;
Node<DataType>* s = new Node<DataType>;
s->data = x;
s->next = NULL;
rear->next = s;
rear = s;
length++;
}
template <class DataType>
bool LinkQueue<DataType>::deQueue(DataType& item) {//需要考虑队列空的问题
if (isEmpty()) {
return false;
}
Node<DataType>* s = front->next;
item = s->data;
front->next = s->next;
if (s->next == NULL) {
rear = front;
}
delete s;
length--;
return true;
}
template <class DataType>
bool LinkQueue<DataType>::getFront(DataType& item) {
if (isEmpty()) {
return false;
}
else {
item = front->next->data;
return true;
}
}
template <class DataType>
bool LinkQueue<DataType>::isEmpty() {
if (front->next == NULL) {
cout << "队列为空" << endl;
return true;
}
else {
return false;
}
}
template <class DataType>
void LinkQueue<DataType>::clearQueue() {
while (front->next) {
Node<DataType>* s = front->next;
front->next = s->next;
if (s->next == NULL)
rear = front;
delete s;
length--;
}
}
template <class DataType>
void LinkQueue<DataType>::displayQueue() {
Node<DataType>* p = front->next;
while (p) {
cout << "[" << p->data.arrivalTime << "," << p->data.duration << "] ";
p = p->next;
}
cout << endl;
}
template <class DataType>
int LinkQueue<DataType>::queueLength() {
return length;
}
//定义单个事件的结构体
typedef struct evnode {
int occurTime;//事件发生的时间
int nType;//事件类型,-1表示到达事件,0-3表示四个窗口的离开事件;
struct evnode* next;//指针域
}evNode;
class EventList {
private:
evNode* head;
public:
EventList();//创建头结点
~EventList();//销毁链表
bool isEmpty();
void addNode(evNode ev);//插入节点要求按照occurTime从小到大排列
bool deleteNode(evNode* firstEv);
void displayNode();
};
EventList::EventList() {
head = new evNode;
head->next = NULL;
}
EventList::~EventList() {
evNode* p = head->next;
while (p != NULL) {
evNode* tmp = p;
p = p->next;
delete tmp;
}
}
bool EventList::isEmpty() {
if (head->next == NULL) {
return true;
}
else {
return false;
}
}
void EventList::addNode(evNode ev) {
evNode* node = new evNode;
node->occurTime = ev.occurTime;
node->nType = ev.nType;
node->next = NULL;
evNode* q;
evNode* p;
q = head;
p = head->next;
if (q->next == NULL) {
head->next = node;
}
else {
while (p != NULL) {
if (p->occurTime > node->occurTime) {
node->next = p;
q->next = node;
break;
}
else {
q = p;
p = p->next;
}
}
if (p == NULL) {
q->next = node;
}
}
}
bool EventList::deleteNode(evNode* firstEv) {
if (isEmpty()) {
return false;
}
evNode* p = head->next;
head->next = p->next;
firstEv->occurTime = p->occurTime;
firstEv->nType = p->nType;
delete p;
return true;
}
void EventList::displayNode() {
evNode* p = head->next;
cout << "显示事件表:";
while (p != NULL) {
cout << "[" << p->occurTime << "," << p->nType << ",";
if (p->next == NULL) {
cout << "-" << "]";
}
else {
cout << "^" << "]" << "->";
}
p = p->next;
}
cout << "\n";
}
int findMin(LinkQueue<Client> queue[], int n) {
int* a = new int[n];
int* b = new int[n];
for (int i = 0; i < n; i++) {
a[i] = queue[i].queueLength();
b[i] = i;
}
for (int j = 0; j < n - 1; j++) {
if (a[j] < a[j + 1]) {
int temp = a[j];
int temp2 = b[j];
a[j] = a[j + 1];
b[j] = b[j + 1];
a[j + 1] = temp;
b[j + 1] = temp2;
}
}
int num = b[n - 1];
delete[] b;
return num;
}
const int CLOSE_TIME = 40;
double simulation() {
int totalTime = 0;//为客户服务总时长
int customerNum = 0; //客户人数
int chcount = 0;
//定义队列数组queue,下标0至3分别表示4个排队窗口队列,-1表示是新客户到达事件
LinkQueue<Client> queue[4];
//建立事件对象链表对象,设定第一个客户到达的事件
EventList evList;
//初始化事件列表,加入第一个节点,起始时间为0,第一个时间为-1(新客户到达事件)
//设置evltem值为[0,-1,NULL];
evNode evltem = { 0,-1,NULL };
evList.addNode(evltem);
//扫描并处理事件列表
while (!evList.isEmpty()) {
chcount = chcount + 1;
cout << "-------------------------第" << chcount << "次循环------------------" << endl;
//删除事件链表中的第一个节点存入evltem
evList.deleteNode(&evltem);
cout << "删除链表中第一个节点存入" << evltem.occurTime << "," << evltem.nType << endl;
if (evltem.nType == -1) {
/*------新客户到达事件-------*/
//客户人数加1
customerNum++;
cout << "是新客户到达事件,请输入durTime和interTime:" << endl;
//输入随机数durTime和interTime 当前客户服务时间,
//下一客户到达时间间隔时间
int durTime, interTime;
cin >> durTime >> interTime;
if (evltem.occurTime + interTime < CLOSE_TIME) {//在银行关门前进行服务
//设定下一客户到达的事件插入事件表
evNode evTemp;
evTemp.occurTime = evltem.occurTime + interTime;
evTemp.nType = -1;
evTemp.next = NULL;
cout << "把下一个客户到达的事件插入事件表" << endl;
evList.addNode(evTemp);
evList.displayNode();
}
//排队人数最少的队列
int min = findMin(queue, 4);
//当前客户进入排队人数最少的队列
Client client;
client.arrivalTime = evltem.occurTime;
client.duration = durTime;
queue[min].enQueue(client);//入队
cout << "当前用户进入人数最少的队列:" << "queue" << min;
queue[min].displayQueue();
//如果当前客户到达的窗口没有人在排队(他是第一个客户)
if (queue[min].queueLength() == 1) {
//设定第一个客户离开银行的事件,插入时间表中
evNode evTemp;
evTemp.occurTime = evltem.occurTime + durTime;
evTemp.nType = min;
evList.addNode(evTemp);
cout << "设定第一个客户离开银行的事件,插入时间表中" << endl;
cout << "显示事件表:" << endl;
evList.displayNode();
}
}
else {
//-----客户离开事件-------
//获得用户所在窗口号(队列号)
int win = evltem.nType;
//将当前要离开的客户从队列中删除,并将当前客户信息存入 client
Client client;
queue[win].deQueue(client);
cout << "将当前要离开的客户从队列中删除" << client.arrivalTime << "," << client.duration << "queue" << win << endl;
queue[win].displayQueue();
//计算客户在银行逗留时间,把当前客户时间累加到totaltime
totalTime = totalTime + client.duration;
//如果还有人在排队,将队头客户离开事件插入事件表
if (queue[win].queueLength() != 0) {
cout << "如果还有人在排队,将队头客户离开事件插入事件表" <<
//获取队头节点数据
queue[win].getFront(client);
//把队头节点的离开事件插入到时间表中
evNode evTemp;
evTemp.occurTime = evltem.occurTime + client.duration;
evTemp.nType = win;
cout << "如果还有人在排队,将队头客户离开事件插入事件表" << evTemp.occurTime << "," << evTemp.nType;
evList.addNode(evTemp);
cout << "显示事件表:";
evList.displayNode();
}
}
}
//计算客户平均处理时间
return totalTime * 1.0 / customerNum;//返回客户平均处理时间
}
int main() {
// 23 4
// 3 1
// 11 3
// 29 2
// 18 4
// 13 5
// 20 30
double time = simulation();
cout << "客户在银行的平均逗留时间是:" << time;
}
参考B站懒猫老师数据结构课程
【懒猫老师-数据结构-(12)队列应用:银行排队模拟(离散事件模拟)】https://www.bilibili.com/video/BV1nE411u7n4?vd_source=be8ba9904d4ffab80d462bfa61683299