数据结构电话客户服务模拟.docx
《数据结构电话客户服务模拟.docx》由会员分享,可在线阅读,更多相关《数据结构电话客户服务模拟.docx(19页珍藏版)》请在冰点文库上搜索。
数据结构电话客户服务模拟
电话客户服务模拟
1、问题描述
一个模拟时钟提供接听电话服务的时间(以分钟记),然后这个时钟将循环的自增一(分钟)直到到达指定时间为止。
在时钟的每个“时刻”,就会执行一次检查来看看当前电话的服务是否已经完成了,如果是,这个电话从电话队列中删除,模拟服务将从队列中取出下一个电话(如果有的话)继续开始。
同时还需要执行一个检查来判断是否有一个新的电话到达。
如果是将其到达时间记录下来,并为其产生一个随机服务时间,这个服务时间也被记录下来,然后这个电话被放入电话队列中,当客户服务人员空闲时,按照先来先服务的方式处理这个队列。
当时钟到达指定时间时,不会再接听新的电话,但是服务将继续,直到电话队列中所有电话都得到处理为止。
当完成上述功能以后,将记录最佳方案,记录客服人员信息,通过桶存储方式来记录和查询信息。
2、基本要求
(1)程序需要的初始数据包括:
客户服务人员的人数,时间限制,电话的到达速率,平均服务时间,客服人员编号,客服人员姓名。
(2)程序产生的结果包括:
处理的电话数,每个电话的平均等待时间,服务总时间,限制时间内接听电话数。
三、工具/准备工作
在开始做课程设计项目前,应回顾或复习相关内容。
需要一台计算机,期中安装有VisualC++6.0、VisualC++2005、VisualC++2005Express、Dev-C++或MinGWDeveloperStudio之一的集成开发环境。
4、分析与实现
由于要计算客户的等待时间,并且每个客户都有接受服务所需的时间,为实现这些功能,对客户加上当前接受服务的时间,具体客户结构类型和服务人员类型如下:
//服务人员类型
structTelephoneServerType
{
charseverNumber[18];//服务人员编号
charseverName[16];//服务人员姓名
boolisEmpty;//是否为空
intobjServerTotalTime;//服务总时间
intobjTelephoneOfLimit;//限制时间内接听电话数
};
//客户类型
structCustomerType
{
unsignedintarrivalTime;//客户到达时刻
unsignedintduration;//客户接受服务所需的时间
unsignedintcurServiceTime;//当前接受服务的时间
};
//服务人员类型
structServerType
{
intserverTotalTime;//服务总时间
inttelephoneOfLimit;//限制时间内接听电话数
};
为了模拟计时,在电话客户服务模拟类中增加表示当前时间的变量curTime,此处时间单位为分钟,为更好地模拟,使用泊松随机数,为模拟客户随机打进电话,需要知道客户到达率(平均每分钟打进电话人数),为模拟客户接受服务的时间,需要知道平均服务时间,为存储服务人员信息,需要创造一个文本,将基桶写入文件中,具体客户服务模拟类声明如下:
template
TelephoneServer:
:
TelephoneServer()
//操作结果:
初始化服务人员信息
{
//初始化数据成员
curTime=0;//当前时间初值为0
totalWaitingTime=0;//总等待时间初值为0
numOfCalls=0;//处理的电话数初值为0
//获得模拟参数
cout<<"输入客户人员的人数(请输入数字):
";
cin>>numOfCustomerServiceStaffs;//输入客户人员的人数
cout<<"输入时间限制(请输入数字):
";
cin>>limitTime;//不再接受新电话的时间
intcallsPerHour;//每小时电话数
cout<<"输入每小时电话数(请输入数字):
";
cin>>callsPerHour;//输入每小时电话数
arrivalRate=callsPerHour/60.0;//转换为每分钟电话数
cout<<"输入平均服务时间(请输入数字):
";
cin>>averageServiceTime;//输入平均服务时间
//分配动态存储空间
callsWaitingQueue=newLinkQueue[numOfCustomerServiceStaffs];//为客服电话等待队列数组分配存储空间
customerServed=newCustomerType[numOfCustomerServiceStaffs];//为客服人员正在服务的客户分配存储空间
servers=newServerType[numOfCustomerServiceStaffs];//为服务人员分配存储空间
//初始化客服人员正在服务的客户
for(inti=0;i{//初始化每个客服人员正在服务的客户
customerServed[i].curServiceTime=customerServed[i].duration=0;//表示还没有人接受服务
servers[i].serverTotalTime=servers[i].telephoneOfLimit=0;//表示还没有工作
}
//设置随机数种子
SetRandSeed();//以当前时间值为随机数种子
ifstreamiFile("telph.dat");//建立输入文件
if(iFile.fail())
{//打开文件失败,表示不存在文件
ofstreamoFile("telph.dat");//建立输出文件
if(oFile.fail())throw("打开文件失败!
");//抛出异常
oFile.close();//关闭文件
}
else
{//存在文件
iFile.close();//关闭文件
}
hashFile.open("telph.dat",ios:
:
in|ios:
:
out|ios:
:
binary);//以读写方式打开文件
if(hashFile.fail())throw("打开文件失败!
");//抛出异常
hashFile.seekg(0,ios:
:
end);//定位到文件尾
intbucketNum=hashFile.tellg()/sizeof(BucketType);//桶数
if(bucketNum
{//桶数不于基桶数,说明文件不完整或已被破坏,应初始化基桶
BucketTypebucket;
intpos;//临时变量
for(pos=0;pos{//初始化基桶
bucket.records[pos].isEmpty=true;//空记录
bucket.next=-1;//无溢出
}
hashFile.clear();//清除标志
hashFile.seekg(0,ios:
:
beg);//定位到文件头
for(pos=0;pos
{//写基桶到文件中
hashFile.write((char*)&bucket,sizeof(BucketType));//写入基桶
}
}
}
类TelephoneServer的Service()辅助函数为客户服务人员服务当前的电话,如果当前客户接受服务的时间还未到达客户服务所需的时间,则继续在为客户提供服务,否则如有客户在等待服务,则从等待队列中取出新客户进行服务,并更新总客户等待时间,具体实现如下:
template
voidTelephoneServer:
:
Service()
//操作结果:
服务当前电话(如有电话)
{
for(inti=0;i{//处理每个客服工作人员提供的服务
if(customerServed[i].curServiceTime{//未到达客户接受服务所需的时间,正在为客户提供服务
customerServed[i].curServiceTime++;//增加客户接受服务的时间
}
else
{//已到达客户接受服务所需的时间,为下一客户提供服务
if(!
callsWaitingQueue[i].Empty())
{//有客户在等待
callsWaitingQueue[i].OutQueue(customerServed[i]);//从等待队列中取出新客户进行服务
totalWaitingTime+=curTime-customerServed[i].arrivalTime;//更新总客户等待时间
}
}
}
}
类TelephoneServer的CheckForNewCall()辅助函数用于生成当前时间打进电话的人数,对每个打进电话的客户,将其插入最短的客服电话等待队列中,具体实现如下:
template
voidTelephoneServer:
:
CheckForNewCall()
//操作结果:
检查是否有新电话,如果有,则将电话添加到电话队列
{
intcalls=GetPoissionRand(arrivalRate);//当前打进电话的人数
for(inti=1;i<=calls;i++)
{//第i个电话
CustomerTypecustomer;//客户
customer.arrivalTime=curTime;//客户到达时间
customer.duration=GetPoissionRand(averageServiceTime);//客户接受服务所需的时间
customer.curServiceTime=0;//当前接受服务的时间
intpos=MinLengthCallWaitingQueue();//最短客服电话等待队列的位置
callsWaitingQueue[pos].InQueue(customer);//客户插入等待队列
numOfCalls++;//处理的电话数
}
}
类TelephoneServer的Display()辅助函数用于在模拟的最后显示处理的总电话数和每个电话的平均等待时间,具体实现如下:
template
voidTelephoneServer:
:
Display()
//操作结果:
显示模拟结果
{
cout<<"处理的总电话数:
"<cout<<"平均等待时间:
"<}
类TelephoneServer的Run()方法实现模拟电话客户服务,当为到达时间限制时,首先检查是否有新电话,如果有,则将电话添加到电话队列,然后客户服务人员再对当前客户进行服务,最后增加时间;当已到达时间限制时,不再检查是否有新电话,但客户服务人员还要对当前客户进行服务,并增加时间,具体实现如下:
template
voidTelephoneServer:
:
Run()
//操作结果:
模拟电话客户服务
{
while(curTime{//未到达时间限制,可检查新电话
CheckForNewCall();//检查是否有新电话,如果有,则将电话添加到电话队列
Service();//进行服务
curTime++;//增加时间
}
while(MinLengthCallWaitingQueue()>0)
{//在客服电话等待队列中还有客户在等待服务
Service();//进行服务
curTime++;//增加时间
}
Display();
}
类TelephoneServer中Hash(constcharseverNumber[18])辅助函数用于生成散列函数值,具体实现如下:
template
longTelephoneServer:
:
Hash(constcharseverNumber[18])
//操作结果:
返回散列函数值
{
longh=0;//散列函数值
for(intpos=0;pos<(int)strlen(severNumber);pos++)
{//依次处理各数字字符
h=(h*10+severNumber[pos]-'0')%b;
}
returnh;//返回散列函数值
}
类TelephoneServer中LocateHelp(constBucketType&bucket,charseverNumber[18])辅助函数用于记录服务人员编号在桶中的位置,具体实现如下:
template
intTelephoneServer:
:
LocateHelp(constBucketType&bucket,charseverNumber[18])
//操作结果:
返回服务人员编号severNumber在桶bucket中的位置
{
for(intpos=0;pos{//依次比较桶中各服务人员信息存储记录
if(!
bucket.records[pos].isEmpty&&
strcmp(bucket.records[pos].severNumber,severNumber)==0)returnpos;//定位成功
}
return-1;//定位失败
}
类TelephoneServer中Locate(BucketType&bucket,long&offset,int&pos,charseverNumber[18])辅助函数用于定位服务人员编号所在的桶,以及在桶中的位置和桶在文件中的位置,具体实现如下:
template
voidTelephoneServer:
:
Locate(BucketType&bucket,long&offset,
int&pos,charseverNumber[18])
//操作结果:
定位服务人员编号severNumber所在的桶bucket,在桶中的位置pos,桶在文件
//中的位置位置offset
{
longh=Hash(severNumber);//散列函数值
offset=sizeof(BucketType)*h;//桶在文件中的位置
hashFile.clear();//清除标志
hashFile.seekg(offset,ios:
:
beg);//文件定位
hashFile.read((char*)&bucket,sizeof(BucketType));//读取基桶
pos=LocateHelp(bucket,severNumber);//定位服务人员信息存储记录在桶中的位置
if(pos==-1)offset=bucket.next;//溢出桶的位置
while(pos==-1&&offset!
=-1)
{//继续在溢出桶中查找
hashFile.clear();//清除标志
hashFile.seekg(offset,ios:
:
beg);//文件定位
hashFile.read((char*)&bucket,sizeof(BucketType));//读到基桶
pos=LocateHelp(bucket,severNumber);//定位服务人员信息存储记录在桶中的位置
if(pos==-1)offset=bucket.next;//后继溢出桶的位置
}
}
类TelephoneServer中LocateEmptyRecordHelp(constBucketType&bucket)辅助函数用于获得空记录的位置,具体实现如下:
template
intTelephoneServer:
:
LocateEmptyRecordHelp(constBucketType&bucket)
//操作结果:
返回空记录位位置
{
for(intpos=0;pos{//依次比较桶中各服务人员信息存储记录
if(bucket.records[pos].isEmpty)returnpos;//定位成功
}
return-1;//定位失败
}
类TelephoneServer中LocateEmptyRecord(BucketType&bucket,long&offset,int&pos,charseverNumber[18])辅助函数用于服务人员编号所在具有空记录的桶,以及桶中空记录的位置,和桶在文件中的位置,具体实现如下:
template
voidTelephoneServer:
:
LocateEmptyRecord(BucketType&bucket,long&offset,
int&pos,charseverNumber[18])
//操作结果:
定位服务人员编号severNumber所在的具有空记录的桶bucket,桶中的空记录位置pos,桶
//在文件中的位置位置offset
{
longh=Hash(severNumber);//散列函数值
offset=sizeof(BucketType)*h;//桶在文件中的位置
hashFile.clear();//清除标志
hashFile.seekg(offset,ios:
:
beg);//文件定位
hashFile.read((char*)&bucket,sizeof(BucketType));//读到基桶
pos=LocateEmptyRecordHelp(bucket);//定位桶中空记录的位置
if(pos==-1)offset=bucket.next;//溢出桶的位置
while(pos==-1&&offset!
=-1)
{//继续在溢出桶中查找
hashFile.clear();//清除标志
hashFile.seekg(offset,ios:
:
beg);//文件定位
hashFile.read((char*)&bucket,sizeof(BucketType));//读到基桶
pos=LocateEmptyRecordHelp(bucket);//定位桶中空记录的位置
if(pos==-1)offset=bucket.next;//后继溢出桶的位置
}
}
类TelephoneServer中Input()辅助函数用于输入记录并且将数据写入通过桶写入到文件中,具体实现如下:
template
voidTelephoneServer:
:
Input()
//操作结果:
输入记录
{
TelephoneServerTypetelph;//服务人员信息存储记录
telph.isEmpty=false;//标记
cout<<"输入服务人员编号:
";
cin>>telph.severNumber;
cout<<"输入服务人员姓名:
";
cin>>telph.severName;
telph.objServerTotalTime=GetTheServerTotalTime();
telph.objTelephoneOfLimit=GetTheTelephoneOfLimit();
BucketTypebucket;//桶
longoffset;//桶在文件中的相应位置
intpos;//服务人员信息存储记录在桶中的位置
Locate(bucket,offset,pos,telph.severNumber);//定位服务人员信息存储记录的位置
if(pos!
=-1)
{//定位成功
cout<<"编号已在散列文件中!
"<}
else
{//定位失败
LocateEmptyRecord(bucket,offset,pos,telph.severNumber);//定位空记录位置
if(pos!
=-1)
{//找到空记录
bucket.records[pos]=telph;//将服务人员信息存储记录赋值给bucket.records[pos]
hashFile.clear();//清除标志
hashFile.seekg(offset,ios:
:
beg);//定位文件
hashFile.write((char*)&bucket,sizeof(BucketType));//写桶
}
else
{
hashFile.clear();//清除标志
hashFile.seekg(0,ios:
:
end);//定位到文件尾
bucket.next=hashFile.tellg();//后继溢出桶位置
hashFile.clear();//清除标