目录
1.程序设计思路
1.框架构想
2.数据结构的选择
2.相应功能的函数实现及程序所需变量
1.模拟器初始化函数
2.事件表相应功能函数实现
3.客户队列相应功能函数实现
4.客户到达事件函数实现
5.客户离开事件函数实现
6.全局变量的设置和宏定义说明
7.模拟器函数实现
3.源程序代码
1.程序设计思路
1.框架构想
? 由于本程序的设计意图在于实现银行的业务模拟,主要功能在于实现两个功能:
1.客户到达银行且在某个办事窗口队列排队和办理事务。????????
2.某个窗口队列的客户完成事务办理,记录逗留时间。
? 最后在银行工作一天时间内记录所有客户的逗留时间并计算出客户平均逗留时间。故程序的整体框架为开始银行模拟器并进行初始化,然后提取发生时间最近的事件并判断事件类型来执行上述1、2两种功能。
2.数据结构的选择
? 本程序需要存储的元素有事件和客户队列两种,由于事件需要经常进行插入操作,故选用链表来实现,而客户队列则选用堆栈队列的方式实现,达到操作方便的目的。实现代码如下图所示:
struct event
{ //定义事件结构体
int occurtime; //事件的发生时间
int Ntype; //事件类型
};
struct customer //定义客户结构体
{
int ArrivalTime; //记录客户到达时间
int Duration; //记录客户办理业务时间
int label;
};
struct eventlist //定义事件链表
{
event ev;
eventlist* next;
};
struct customerqueue //定义队列结构体
{
customer* base; //队列基地址
int rear; //队列尾地址
int length;
};
2.相应功能的函数实现及程序所需变量
1.模拟器初始化函数
? 需要将事件表、客户队列初始化,并且清空TotalTime、CustomNum两个计数器,且插入第一个即将发生的事件。
void OpenForDay() //银行模拟器初始化
{
TotalTime = CustomerNum = 0; //将两个计数器清零
Init_eventlist(); //事件表初始化
en.occurtime = 0, en.Ntype = 0;
Insert_List(); //在事件链表中选择合适位置插入
Init_customer_queue(); //客户队列初始化
}
2.事件表相应功能函数实现
? 事件表所需要的插入、初始化、删除等操作函数实现:
void Init_eventlist() //初始化事件表
{
ev_list = (eventlist*)malloc(sizeof(eventlist));
ev_list->next = nullptr;
}
void Insert_List(event q = en) //将事件插入事件表
{
eventlist* p = ev_list->next, *prior = ev_list;
eventlist* temp = (eventlist*)malloc(sizeof(eventlist));
while (p != nullptr)
{
if (cmp(q, p->ev) < 0) //利用比较函数来判断相应事件发生的时间,将当前事件插入到对应的位置
{
temp->ev = q;
prior->next = temp;
temp->next = p;
break;
}
else
{
p = p->next;
prior = prior->next;
}
}
if (p == nullptr) //事件表为空则直接插入
{
temp->ev = q;
prior->next = temp;
temp->next = nullptr;
}
}
int cmp(event a, event b) //比较两个事件发生时间的先后顺序
{
if (a.occurtime > b.occurtime)
return 1;
else return -1;
}
eventlist* DelFirst_List() //删除事件表头元素节点且获得事件信息
{
eventlist* p = ev_list->next;
ev_list->next = ev_list->next->next;
return p;
}
void GetItem_List(eventlist* p) //将节点p中的值赋给en
{
en.occurtime = p->ev.occurtime;
en.Ntype = p->ev.Ntype;
}
? 上述的功能函数都是链表中较为基础的一些操作,比较容易看懂,只有插入函数接口使用了默认变量值需要注意一下。?
3.客户队列相应功能函数实现
? 客户队列所需要的插入、删除头结点、寻找最短队列、初始化等功能函数实现:
int MiniQueue() //寻找人数最少的队列
{
int flag = 0;
for (int i = 0; i < Queue_Number; i++)
if (queue[i].length < queue[flag].length)
flag = i;
return flag;
}
void EnQueue(customerqueue& q) //插入队列
{
q.base[q.rear] = record;
q.rear = q.rear + 1;
q.length++;
return;
}
void DelQueue(int i) //删除队首节点
{
record.ArrivalTime = queue[i].base[0].ArrivalTime;
queue[i].base++;
queue[i].length--;
queue[i].rear--;
}
void Init_customer_queue() //初始化客户队列
{
for (int i = 0; i < Queue_Number; i++)
{
queue[i].base = (customer*)malloc(sizeof(customer) * MaxQueue_Length);
queue[i].rear = 0;
queue[i].length = 0;
}
}
4.客户到达事件函数实现
? 客户到达后,客户总量计数器CusNum加一,且随机生成业务办理时间和下一个客户到达时间两个随机数,将下一个客户到达事件插入事件表同时将当前时间到达的客户插入最短的客户队列中,对应代码:
void CustomerArrived(int Closetime) //客户到达
{
++CustomerNum;
record.ArrivalTime = en.occurtime;
record.Duration = random(20);
record.label = CustomerNum;
int InterTime = random(10) + 1;
int t = en.occurtime + InterTime;
if (t < Closetime) //银行没有关门则将下一个客户到达事件插入事件表中
{
event temp;
temp.occurtime = t;
temp.Ntype = 0;
Insert_List(temp);
}
int i = MiniQueue();
EnQueue(queue[i]); //将刚到达的客户放到人数最短的队列中
if (queue[i].length == 1) //若队列仅有一个人则设置当前队列的一个离开事件,不能直接设置的原因是存在排队的时间
{
event temp;
temp.occurtime = en.occurtime + record.Duration;
temp.Ntype = i + 1;
Insert_List(temp);
}
}
? 需要注意的是如果插入的客户队列仅有当前客户一个人,还需要生成对应客户离开事件插入到事件表中,不然会造成该客户永远不离队的情况,需要注意!
5.客户离开事件函数实现
? 客户离开时,需要注意客户的逗留时间不是他办理业务的时间而是他办理业务加上排队时间。另外,当某个队列有人离开时,如果该队列不为空则需要再设置下一个客户的离开事件。
void CustomerDeparture() //客户离开
{
int i = en.Ntype - 1;
DelQueue(i);
TotalTime += en.occurtime - record.ArrivalTime; //计算客户累计逗留时间
if (queue[i].length != 0) //若队列不为空则设定第i队列的一个离开时间并插入事件表
{
event temp;
temp.occurtime = en.occurtime + queue[i].base[0].Duration;
temp.Ntype = en.Ntype;
Insert_List(temp);
}
}
6.全局变量的设置和宏定义说明
? 由于程序较为简单,且不存在对外接口,为了操作方便设置了几个全局变量。
eventlist* ev_list; //事件表
event en; //事件
customerqueue queue[Queue_Number]; //客户队列
customer record; //客户记录
int TotalTime = 0, CustomerNum = 0; //总时间和客户总量
? 所用宏定义:
define MaxQueue_Length 100
#define Queue_Number 4
#define random(x) rand() % (x) //定义随机数生成器
7.模拟器函数实现
void Bank_Simulation(int CloseTime) //银行模拟函数
{
OpenForDay();
eventlist* p = (eventlist*)malloc(sizeof(eventlist));
while (ev_list->next != nullptr)
{
p = DelFirst_List();
GetItem_List(p);
if (en.Ntype == 0)
CustomerArrived(CloseTime);
else CustomerDeparture();
show_event();
}
cout << "The Average Time is " << (float)TotalTime / CustomerNum << '\n';
}
3.源程序代码
#include <iostream>
#include <cstdlib>
#include <ctime>
#include <windows.h>
#define MaxQueue_Length 100
#define Queue_Number 4
#define random(x) rand() % (x) //定义随机数生成器
using namespace std;
struct event
{ //定义事件结构体
int occurtime; //事件的发生时间
int Ntype; //事件类型
};
struct customer //定义客户结构体
{
int ArrivalTime; //记录客户到达时间
int Duration; //记录客户办理业务时间
int label;
};
struct eventlist //定义事件链表
{
event ev;
eventlist* next;
};
struct customerqueue //定义队列结构体
{
customer* base; //队列基地址
int rear; //队列尾地址
int length;
};
eventlist* ev_list; //事件表
event en; //事件
customerqueue queue[Queue_Number]; //客户队列
customer record; //客户记录
int TotalTime = 0, CustomerNum = 0; //总时间和客户总量
void Init_eventlist() //初始化事件表
{
ev_list = (eventlist*)malloc(sizeof(eventlist));
ev_list->next = nullptr;
}
void Init_customer_queue() //初始化客户队列
{
for (int i = 0; i < Queue_Number; i++)
{
queue[i].base = (customer*)malloc(sizeof(customer) * MaxQueue_Length);
queue[i].rear = 0;
queue[i].length = 0;
}
}
int cmp(event a, event b) //比较两个事件发生时间的先后顺序
{
if (a.occurtime > b.occurtime)
return 1;
else return -1;
}
void Insert_List(event q = en) //将事件插入事件表
{
eventlist* p = ev_list->next, *prior = ev_list;
eventlist* temp = (eventlist*)malloc(sizeof(eventlist));
while (p != nullptr)
{
if (cmp(q, p->ev) < 0) //利用比较函数来判断相应事件发生的时间,将当前事件插入到对应的位置
{
temp->ev = q;
prior->next = temp;
temp->next = p;
break;
}
else
{
p = p->next;
prior = prior->next;
}
}
if (p == nullptr) //事件表为空则直接插入
{
temp->ev = q;
prior->next = temp;
temp->next = nullptr;
}
}
eventlist* DelFirst_List() //删除事件表头元素节点且获得事件信息
{
eventlist* p = ev_list->next;
ev_list->next = ev_list->next->next;
return p;
}
void GetItem_List(eventlist* p) //将节点p中的值赋给en
{
en.occurtime = p->ev.occurtime;
en.Ntype = p->ev.Ntype;
}
int MiniQueue() //寻找人数最少的队列
{
int flag = 0;
for (int i = 0; i < Queue_Number; i++)
if (queue[i].length < queue[flag].length)
flag = i;
return flag;
}
void EnQueue(customerqueue& q) //插入队列
{
q.base[q.rear] = record;
q.rear = q.rear + 1;
q.length++;
return;
}
void DelQueue(int i) //删除队首节点
{
record.ArrivalTime = queue[i].base[0].ArrivalTime;
queue[i].base++;
queue[i].length--;
queue[i].rear--;
}
void show_event() //显示当前事件信息
{
if (en.Ntype == 0)
{
cout << "The " << CustomerNum << " customer arrives at the bank\n";
cout << "The customer`s arrivaltime is: " << en.occurtime << '\n';
cout << "His duration time is: " << record.Duration << '\n';
}
else
{
cout << "The " << en.Ntype << " queue`s customer leaves\n";
cout << "His staying time is: " << en.occurtime - record.ArrivalTime << '\n';
}
cout << "TotalTime now is: " << TotalTime << "\n\n\n";
Sleep(0);
}
void CustomerDeparture() //客户离开
{
int i = en.Ntype - 1;
DelQueue(i);
TotalTime += en.occurtime - record.ArrivalTime; //计算客户累计逗留时间
if (queue[i].length != 0) //若队列不为空则设定第i队列的一个离开时间并插入事件表
{
event temp;
temp.occurtime = en.occurtime + queue[i].base[0].Duration;
temp.Ntype = en.Ntype;
Insert_List(temp);
}
}
void CustomerArrived(int Closetime) //客户到达
{
++CustomerNum;
record.ArrivalTime = en.occurtime;
record.Duration = random(20);
record.label = CustomerNum;
int InterTime = random(10) + 1;
int t = en.occurtime + InterTime;
if (t < Closetime) //银行没有关门则将下一个客户到达事件插入事件表中
{
event temp;
temp.occurtime = t;
temp.Ntype = 0;
Insert_List(temp);
}
int i = MiniQueue();
EnQueue(queue[i]); //将刚到达的客户放到人数最短的队列中
if (queue[i].length == 1) //若队列仅有一个人则设置当前队列的一个离开事件,不能直接设置的原因是存在排队的时间
{
event temp;
temp.occurtime = en.occurtime + record.Duration;
temp.Ntype = i + 1;
Insert_List(temp);
}
}
void OpenForDay() //银行模拟器初始化
{
TotalTime = CustomerNum = 0; //将两个计数器清零
Init_eventlist(); //事件表初始化
en.occurtime = 0, en.Ntype = 0;
Insert_List(); //在事件链表中选择合适位置插入
Init_customer_queue(); //客户队列初始化
}
void Bank_Simulation(int CloseTime) //银行模拟函数
{
OpenForDay();
eventlist* p = (eventlist*)malloc(sizeof(eventlist));
while (ev_list->next != nullptr)
{
p = DelFirst_List();
GetItem_List(p);
if (en.Ntype == 0)
CustomerArrived(CloseTime);
else CustomerDeparture();
show_event();
}
cout << "The Average Time is " << (float)TotalTime / CustomerNum << '\n';
}
int main()
{
int closetime;
cout << "Please ensure a time for the bank to close\n";
cin >> closetime;
cout << "The bank simulation is beginning\n\n\n";
srand(time(0));
Bank_Simulation(closetime);
return 0;
}
? 以上就是本人所写程序的源代码,本文章主要介绍了本人的一些程序设计思路及一些需要注意的坑,所写程序相对比较简单,设计思路也相对来说比较直接,采用的数据结构也是链表和堆栈队列相对基础的结构,欢迎大家批评指正。
|