一、实验目的
(1)掌握队列的链式存储结构
(2)掌握队列的基本操作,并能进行应用实践
(3)使用C/C++语言和队列实现”银行叫号系统“专题
二、实验任务
设计一个控制台程序,模拟银行排队业务,要求实现功能:
(1)输出程序界面,提示客户输入银行窗口数量和开放窗口时间
(2)客户随机时间进入银行,程序在事件表中记录客户进入时间和离开时间,并将客户排入窗口队列,办理完业务后退出队列
三、实验代码
1.事件链表
1.1 EventList.h
#pragma once
#include "pch.h"
#include "defineConst.h"
typedef struct Event
{
int time;//发生时刻
int type;//事件类型:0表示顾客到达;1~N表示顾客从N号窗口离开
struct Event *next;
}Event,*EventList;
int InitList(EventList &pList); //初始化链表
int OrderInsert(EventList &pList, Event sEvent); //按发生时刻的顺序向链表中插入元素
int isEmptyList(EventList pList);
int delFirst(EventList &pList, Event *pEvent);
int ListTravel(EventList pList);
1.2 EventList.cpp
#include "pch.h"
#include "EventList.h"
#include
#include
int InitList(EventList &pList)//初始化链表
{
pList = (EventList)malloc(sizeof(Event));//开辟空间
pList ->next= NULL;//下一个为空
return OK;
}
int OrderInsert(EventList &pList, Event sEvent)//插入元素
{
//临时变量,用于在链表中插入结点
Event *pafter, *pbefore;
pbefore = pList;
pafter = pList->next;
//比较事件发生的时间
while (pafter != NULL && sEvent.time > pafter->time)
{
pbefore = pafter;
pafter = pafter->next;
}
//创建一个新结点挂在Before和After两个结点之间
pbefore->next = (Event *)malloc(sizeof(Event));
//对新结点赋值
pbefore->next->time = sEvent.time;
pbefore->next->type = sEvent.type;
pbefore->next->next = pafter;
return OK;
}
int isEmptyList(EventList pList)//判断链表是否为空
{
if (pList->next ==NULL)
return TRUE;
else
return FALSE;
}
int delFirst(EventList & pList, Event *pEvent)//删除首结点
{
Event *ptmp;
if (isEmptyList(pList))
{
printf("链表为空,无可删除节点");
return ERROR;
}
else
{
//删除链表首结点
ptmp = pList->next;
pList->next = ptmp->next;
*pEvent = *ptmp;//保存数值
free(ptmp);//释放内存
return OK;
}
}
int ListTravel(EventList pList)//遍历链表
{
Event *ptmp;
ptmp = pList;
while (ptmp->next != NULL)
{
ptmp = ptmp->next;
if (ptmp->type == 0)
printf("第%d分钟,下一名顾客即将到来。\n", ptmp->time);
else
printf("第%d分钟, %d号窗口顾客即将离开。\n", ptmp->time, ptmp->type);
}
printf("\n");
return OK;
}
2.链式队列
2.1 LinkedQueue.h
#pragma once
#include "pch.h"
#include "defineConst.h"
typedef struct QElemType
{
int time;
int duration;
struct QElemType *next;
}QElemType;
typedef struct LinkedQueue
{
QElemType *front;//头指针
QElemType *rear;//尾指针
}LinkedQueue;
int InitQueue(LinkedQueue *pQueue);
int isemptyQueue(LinkedQueue *pQueue);
int delFirstQueue(LinkedQueue *pQueue,QElemType *pQElem);
int enQueue(LinkedQueue *pQueue, QElemType sQElem);
int queueLength(LinkedQueue *pQueue);
int getHead(LinkedQueue *pQueue, QElemType * pQElem);
int queueTravel(LinkedQueue *pQueue);
2.2 LinkedQueue.cpp
#include "pch.h"
#include"LinkedQueue.h"
#include
int InitQueue(LinkedQueue *pQueue)
{
//分配内存
pQueue->front = pQueue->rear = (QElemType *)malloc(sizeof(QElemType));
if (pQueue->front == NULL)
{
printf("分配内存失败!\n");
exit(-1);
}
pQueue->front->next = NULL;
return OK;
}
int isemptyQueue(LinkedQueue *pQueue)
{
if (pQueue->front == pQueue->rear)
return true;
else
return false;
}
int delFirstQueue(LinkedQueue *pQueue, QElemType *pQElem)
{
QElemType *ptmp;//临时结点指针
if (isemptyQueue(pQueue))
{
printf("队列为空,不能继续出队列\n");
return ERROR;
}
else
{
ptmp = pQueue->front->next; //让ptmp指向队列的首节点的后一个元素
*pQElem = *ptmp; //将首节点的值复制给pQElem
pQueue->front->next = ptmp->next;//front指针向后移动一位,删除这个结点
if (pQueue->rear == ptmp)
{
pQueue->rear = pQueue->front;
}
free(ptmp);
return OK;
}
}
int enQueue(LinkedQueue *pQueue, QElemType sQElem)//结点入队操作
{
QElemType *ptmp;//临时结点指针
ptmp = (QElemType *)malloc(sizeof(QElemType));
if (ptmp == NULL)
{
printf("分配内存失败!");
exit(-1);
}
else
{
//尾节点指向新入队的元素
*ptmp=sQElem;
ptmp->next = NULL;
pQueue->rear->next = ptmp;
pQueue->rear = ptmp;
}
return OK;
}
int queueLength(LinkedQueue *pQueue)//获取队列长度
{
QElemType *ptmp;//临时结点指针
int count = 0;
ptmp = pQueue->front->next;//队列第一个结点
while (ptmp != NULL)
{
count++;
ptmp = ptmp->next;
}
return count;
}
int getHead(LinkedQueue *pQueue, QElemType * pQElem)
{
if (isemptyQueue(pQueue))
{
printf("队列为空!");
return ERROR;
}
*pQElem = *(pQueue->front->next);
return OK;
}
int queueTravel(LinkedQueue *pQueue)
{
QElemType *ptmp;//临时结点指针
if (isemptyQueue(pQueue))
{
printf("队列为空!\n");
return ERROR;
}
ptmp = pQueue->front->next;//队列第一个结点
while (ptmp != NULL)
{
printf("[到达时刻:第%d分钟,服务时长:%d分钟]\n",ptmp->time,ptmp->duration);
ptmp = ptmp->next;
}
printf("\n");
return OK;
}
3.主要业务功能
3.1 BankService.h
#pragma once
#include "pch.h"
#include "defineConst.h"
#include
void Initialize();
void CustomerArrived();
void CustomerLeaved();
int ShortestQueue();
void PrintQueue();
void PrintEventList();
void BankSimulation();
3.2 BankService.cpp
#include "pch.h"
#include "EventList.h"
#include "LinkedQueue.h"
#include"BankService.h"
#include
#include
#include
#define Maxsize 20//银行服务窗口最大数量
int gWindowNum;//银行服务窗口数
int gCustomerNum;//客户总人数
int gTotalTime;//总服务时间
int gCloseTime;//银行关闭时间
EventList gEventList;//事件列表
Event gEvent;//事件
LinkedQueue gQueue[Maxsize];//队列数组
QElemType gCustomer;//队列结点
void Initialize()//初始化数据
{
int i;
gTotalTime = 0;
gCustomerNum = 0;
InitList(gEventList);//初始化事件列表
//服务窗口个数
printf("请输入银行服务窗口个数(1~20):");
scanf_s("%d", &gWindowNum);
while (gWindowNum<1 || gWindowNum>Maxsize)
{
printf("请输入1到%d之间的整数:", Maxsize);
scanf_s("%d", &gWindowNum);
}
//服务关闭时间
printf("请输入服务关闭时间(超过这个时间就不再接纳新顾客)(单位:分钟):");
scanf_s("%d", &gCloseTime);
while (gCloseTime < 1)
{
printf("请输入大于零的整数:");
scanf_s("%d", &gCloseTime);
}
//为每一个窗口建立一个空队列
for (i = 0;i < gWindowNum;i++)
{
InitQueue(&gQueue[i]);
}
}
void CustomerArrived()//处理客户到达事件
{
QElemType sQElem;
Event sEvent;
int index;//排队人数最少的窗口编号
int arrivetime;//客户到达时间
int duration;//业务办理时间
printf("当前时刻:第%d分钟\n", gEvent.time);
//顾客到达的时间,在上一位顾客之后1~5分钟
arrivetime = gEvent.time+ rand() % 5 + 1;
duration = rand() % 21 + 10;//办理业务时间为10~30分钟
if (arrivetime < gCloseTime)//服务尚未关闭
{
gCustomerNum++;
//新顾客到达事件
sEvent.time = arrivetime;
sEvent.type = 0;
OrderInsert(gEventList, sEvent);
//顾客进入人数最少的窗口排队
sQElem.time = gEvent.time;//入队时刻
sQElem.duration = duration;//办理业务时间
index = ShortestQueue();
enQueue(&gQueue[index], sQElem);//入列
//如果恰好排在了队首,预定离开事件
if (queueLength(&gQueue[index]) == 1)
{
//记录顾客从第index+1号号窗口离开(因为索引从0开始)
sEvent.time =gEvent.time + duration;
sEvent.type = index + 1;
OrderInsert(gEventList, sEvent);
}
}
else//银行排队服务关闭,不再接受新客户
printf("\n排队服务以关闭,不再接受新客户!\n");
}
void CustomerLeaved()//处理客户离开事件
{
Event sEvent;
int index = gEvent.type - 1;//队列编号为窗口编号-1
delFirstQueue(&gQueue[index], &gCustomer);//删除队首节点
printf("\n顾客离开时间:%d", gEvent.time);
gTotalTime += gCustomer.duration;//记录服务时间
//如果队列不为空,则预定下一位顾客从第index+1窗口离开
if (isemptyQueue(&gQueue[index]))
{
getHead(&gQueue[index], &gCustomer);//获得下一位顾客
// 记录离开事件
sEvent.time = gEvent.time + gCustomer.duration;
sEvent.type = index + 1;
OrderInsert(gEventList, sEvent);
}
}
int ShortestQueue()
{
int i = 0;
int min = 9999;//最短队列的长度
int index = -1;//最短队列的编号
int length = 0;
//遍历各个窗口,比较哪个窗口排队的人数最少
for (int i = 0;i < gWindowNum;i++)
{
length = queueLength(&gQueue[i]);
if (min > length)
{
min = length;
index=i;
}
}
return index;
}
void PrintQueue()//显示当前窗口队列
{
int i;
printf("\n窗口排队状态:\n");
for (i = 0;i < gWindowNum;i++)
{
printf("%d号窗口:\n",i+1);
queueTravel(&gQueue[i]);
}
printf("\n");
}
void PrintEventList()//显示当前事件表
{
printf("\n事件表状态:\n");
ListTravel(gEventList);
}
void BankSimulation()//银行排队模拟
{
//随机数发生器,用于模拟随机用户排队事件
//根据当前系统时间初始化随机数种子
srand((unsigned) time(NULL));
//准备开业
Initialize();
//第一个顾客到来
gEvent.time = 0;
gEvent.type = 0;
OrderInsert(gEventList, gEvent);
//处理排队列表
while (!isEmptyList(gEventList))
{
delFirst(gEventList, &gEvent);
//处理顾客事件
if (gEvent.type == 0)
CustomerArrived();
else
CustomerLeaved();
//显示当前事件列表,以及排队情况
PrintEventList();
PrintQueue();
//暂停一会,便于观察输出内容
system("PAUSE");
}
//平均服务时间
printf("\n");
printf("客服平均服务时间:%f分钟\n", (float)gTotalTime / gCustomerNum);
system("PAUSE");
}
4.主函数
#include "pch.h"
#include"defineConst.h"
#include"BankService.h"
#include "EventList.h"
#include"LinkedQueue.h"
#include
int main()
{
BankSimulation();
}