【数据结构】(五)队列,链式队列(银行排队算法)
(一)队列:(如果用循环将使算法时间变得复杂,所以为了提高运算效率,引入队列)

(1)假溢出:(为了解决假溢出,引入循环队列)

(2)循环队列:(判断空满条件)

其中方法二:

(3)队列的创建:(所有的引用修改都是为了可以传出去而使用的)
C++:

C语言:

(4)操作:
入队:

出队:

在主函数中输出item:

改为C++中语句:

读取对头元素:

(二)链式队列:
C++:







(2)区别:

(三)银行排队(离散事件模拟)问题:

表示:
如16,19,23都表示客户所用时间;
例如:16 2 -->表示在第二个窗口花了16分钟,对应5 11(排队5分钟,业务11分钟)
算法:(先图解,最后会有对应代码块)



还需要一个链表来存储和处理事件:


操作:cpp


代码:
List.h文件
#pragma once
#include <iostream>
using namespace std;
#include <string>
//*************----《链表初始化定义》----***********//
typedef struct evNode
{
int occurtime; //事件发生时间
int nType; //事件类型:-1表示到达,0~3表示四个窗口
struct evNode* next;
}evNode;
class EventList
{
private:
evNode* head; //头指针
int length;
public:
EventList() //构造函数
{
head = new evNode;
head->next = NULL;
length = 0;
}
~EventList() //析构函数,删除节点,清空
{
//释放再堆区开辟的所有节点
//保存释放的下一个节点
while (head->next)
{
evNode* p = head->next->next;
delete(head->next);
head->next = p;
}
length = 0;
}
bool isEmpty() //判断是否为空
{
if (length == 0)
{
return true;
}
else
{
return false;
}
}
void addNode(EventList List, evNode* eventItem) //向链表插入数据
{
//插入是要按离开或者到达的时间顺序进行插入
evNode* p = new evNode;
p = eventItem;
//对链表进行遍历,找到新用户该插入的位置
evNode* qi, * hou; //前后指针,用于查找插入排序
qi = List.head;
hou = List.head->next;
while (hou != NULL)
{
if (p->occurtime <= hou->occurtime)
{
//将新用户节点插在该节点前面
p->next = hou;
qi->next = p;
qi->next->next = hou;
break;
}
qi = hou;
hou = hou->next;
}
qi->next = p;
length++;
}
void deleteNode(EventList List, evNode* firstNode) //对链表删除数据
{
evNode* p = new evNode;
p = List.head->next;
firstNode = p;
List.head = p->next;
delete(p);
p = NULL;
length--;
}
void displayNode() //遍历数据
{
evNode* p = head->next;
while (p)
{
if (p->nType == -1)
{
cout << "新用户到达时间为:" << p->occurtime << endl;
}
else
{
cout << p->nType << "号窗口的用户离开时间为:" << p->occurtime << endl;
}
p = p->next;
}
}
};
Queue.h文件:
#pragma once
#include <iostream>
using namespace std;
#include <string>
//************----《队列初始化定义》----************//
//定义银行客户,Client作为队列的data域
typedef struct Client
{
int arrivetime; //客户到达银行时间
int duration; //客户办理业务时间
}Client;
struct Node
{
Client data; //包含客户信息
struct Node* next;
};
class Queue //银行窗口队列类
{
private:
Node* front; //头尾指针
Node* rear;
int length; //队列长度,因为插入时会标记不同的窗口队列,所以不必担心length加重的问题
public:
Queue() //建立头节点,初始化属性
{
front = new Node;
rear = front;
front->next = NULL;
length = 0;
}
~Queue() //释放队列空间
{
if (front == rear)
{
return;
}
else
{
while (front) //直到删完为止
{
rear = front->next;
delete(front);
front = rear;
}
length = 0;
}
}
void enQueue(Client person) //入队
{
//不用判断队列是否为满,因为是链式存储
//头插
Node* p=new Node;
p->data = person;
p->next = NULL;
rear->next = p;
rear = p;
length++;
}
bool deQueue() //出队
{
//队列为空,返回假
if (front == rear)
{
return false;
}
//进行头删
Node* p = front->next;
front->next = p->next;
//判断删除的是否是最后一个节点,是的话把rear指向头结点
if (p == rear)
{
rear = front;
}
delete(p);
p = NULL;
length--;
return true;
}
bool getQueue(Client* item) //获取队头元素到item所☞单元
{
if (length == 0)
{
cout << "无对头元素" << endl;
system("pause");
exit(0);
}
else
{
Node* p ;
p = front->next;
*item = p->data;
delete(p);
return true;
}
}
bool isEmpty() //判断是否为空
{
if (length == 0)
{
return true;
}
else
return false;
}
void clearQueue() //清空队列
{
//清空除头结点以外的节点
Node* p;
p = front->next;
while (p)
{
Node* nextNode = p;
p = p->next;
delete(nextNode);
}
p = NULL;
//尾指针更新到头指针处
front->next = NULL;
rear = front;
length = 0;
}
int queueLength() //获取元素个数
{
return length;
}
};
cpp文件:
#include "Queue.h"
#include "List.h"
#include<time.h>
#define Closetime 40 //银行关门时间
int findMin(Queue queue[], int len);
//现写出银行业务活动如下:
//模仿
double simulation()
{
//为客户服务的总时长
int totalTime = 0;
//客户人数
int customerNum = 0;
//初始化四个窗口队列
Queue queue[4];
//初始化事件链表对象
EventList List;
//初始化一个客户结构体
Client person;
//设定第一个客户到达的事件
evNode eventItem = { 0, -1, NULL };
//将第一个客户放到事件链表中
List.addNode(List,&eventItem);
//判断事件链表是否为空,不为空取出事件链表中第一个事件节点,判断是用户到达事件还是用户离开事件
while (!List.isEmpty())
{
evNode firstNode;
List.deleteNode(List,&firstNode); //弹出(读取)链表第一个数同时在链表中删除第一个数
cout << "第一个事件类型:" << firstNode.nType<<" ";
if (firstNode.nType == -1) //-1表示客户刚到
{
customerNum++; //客户人数加一
//生成随机函数-->服务时间,-->下一位顾客到来时间
int duringTime = rand() % 30 + 1; //接受服务时间范围是1到30
int nextcustomertime = rand() % 20 + 1; //下一个用户到来的间隔时间范围是1到20
cout << "当前客户接受服务所用时间: " << duringTime << endl;
//下一个新用户到来的时间---下一个到来事件发生的时间
//要判断下一个用户到来的时候,银行有没有关门
//当前新用户到达时间+间隔时间
if (firstNode.occurtime < Closetime)
{
//设定下一个用户的到达事件插入事件表
evNode nextPerson;
//表示下一个顾客到达时间,方式
nextPerson = { firstNode.occurtime + nextcustomertime,-1,NULL };
cout << "下一个用户到达时间: " << nextPerson.occurtime << " ";
List.addNode(List,&nextPerson);
}
//把当前到达的用户,放到当前排队人数最少的队列中
//若四个队列排队人数相同,就按队列的顺序从下标小的先插入
int min = findMin(queue, 4);
cout << "去" << min << "窗口排队最好" << endl;
//当前客户进入人数最少的队列
//先对客户结构体进行赋值
person = { firstNode.occurtime , duringTime };
//入队
queue[min].enQueue(person);
//入队完了之后,判断当前客户是不是窗口的第一个人,如果是就要把他的离开事件放入事件表中
if (queue[min].queueLength() == 1)
{
evNode Putincust = { firstNode.occurtime + duringTime, min, NULL };
cout << "用户离开时间为: " << Putincust.occurtime << " ";
cout << "离开窗口: " << min <<"\n\n"<< endl;
//将离开事件插入事件链表中
List.addNode(List,&Putincust);
}
}
else //表示处理的是用户离开事件
{
//记录该用户从几号窗口离开
int index = firstNode.nType;
//获取队头元素
Client leaver;
queue[index].getQueue(&leaver);
//客户离开的时候,要累积客户的逗留时长
totalTime = leaver.duration;
//出队
queue[index].deQueue();
//判断出完队后,当前队列是否为空,如果为空,就不管
//如果还有下一个用户,就要把下一个用户的离开事件放入事件表中
if (queue[index].queueLength() != 0)
{
Client nextPer;
queue[index].getQueue(&nextPer);
//离开的时间等于到达的时间加上逗留的时间
evNode tempNode = { nextPer.arrivetime + nextPer.duration,index,NULL };
List.addNode(List,&tempNode);
}
}
cout << "当前正在处理的事件" << endl;
cout << endl;
}
//计算客户的平均逗留时间
cout << "\n\n用户访问总数: " << customerNum << " ";
cout << "总时间" << totalTime << endl;
return totalTime / customerNum;
}
int findMin(Queue queue[], int len) //找出排队人数最少的窗口下标
{
int min = queue[0].queueLength();
int Index = 0;
for (int i = 0; i < len; i++)
{
if (min < queue[i].queueLength())
{
min = queue[i].queueLength(); //多长
Index = i; //那个窗口
}
else
{
continue;
}
}
return Index;
}
int main()
{
srand(unsigned int((time(NULL)))); //随机函数
double num = simulation();
cout << "用户平均服务时间: " << num << endl;
system("pause");
return 0;
}
结果:

本文介绍了数据结构中的队列,包括循环队列和链式队列的概念及其在银行排队(离散事件模拟)问题中的应用。通过C++和C语言展示了队列的创建、入队、出队操作,并详细解释了银行排队问题的算法实现,涉及到事件处理的链表数据结构。
(循环)队列,链式队列(银行排队(离散事件模拟)算法)&spm=1001.2101.3001.5002&articleId=115493225&d=1&t=3&u=d6c740858d664c71aa05c45571ebc0ec)
1715

被折叠的 条评论
为什么被折叠?



