题目
模拟网上书店的电话接待台接电话(离散事件)的过程。用户在打电话咨询时,先输入自己的标识(如姓名或会员
号),然后进入排队等待被接听电话。xauat 服务人员会根据该用户在书店已购买书籍的累计消费情况对拨入的电话进
行排序。累计消费超过 3000 元的为 1 类用户,最先得到服务;累计消费不到 3000 元、但已满 2000 元的 2 类用户在没
有 1 类用户情况下会得到服务;累计消费不满 2000 元、但已满 1000 元的 3 类用户在没有前两类用户情况下会得到服
务;累积消费不满 1000 元的用户为 4 类用户,在没有前三类用户情况下会得到服务。同类用户根据时间先后确定被接
听的次序。
这些离散事件事先存入文件 sample.txt,程序接收的离散事件需要从 sample.txt 进行,因此程序在运行时需要使用
输入重定向的方式将标准输入流指定为 sample.txt。
该文件格式如下:
首行为整数 N,表明文件接下来有 N 行离散事件(需要接听的电话)。
接下来的 N 行对应 N 项拨入电话,每行离散事件包含 4 项信息,之间使用一个空格隔开。信息格式如下:
<timestamp> <Name> <status> <duration>
<timestamp>
指该电话的拨入时间点,其值为当时所对应的系统时间片编号(从 0 开始算起)。<Name>
指拨入电话的用户姓名(不考虑重名情况),姓名是字符串,中间不允许有空格。<status>
指该用户的等级,从 1 至 4,按照上面的叙述,根据累计消费额分成 4 类用户。<duration>
指该离散事件需要持续的时间片长度。
存储离散时间的示例输入文件 sample.txt 如下(分割线中内容):
---------------------------------------------
3 <---表明下面共有 3 行,对应 3 通拨入的电话
0 Andrew 1 2 <---表明 1 类用户 Andrew 在 0 时间片拨入电话,需持续 2 个时间片(将占用 0、1 时间片)
0 Chris 4 1 <---表明 4 类用户 Chris 在 0 时间片拨入电话,需持续 1 个时间片
1 Brian 2 1 <---表明 2 类用户 Brian 在 1 时间片拨入电话,需持续 1 个时间片
--------------------------------------------- 我们可以分析上面的数据,首时间片 0 号开始时,有两通电话生成,一个是 1 类用户 Andrew ,一个是 4 类用户
Chris,则应先接 1 类用户 Andrew 电话,由于其需持续两个时间片,故应占 0、1 两个时间片。因此 0 号时间片
中系统应输出有两通电话的信息,同时还要输出开始处理 1 类用户 Andrew 电话。
当 1 号时间片开始时,有 1 通电话生成,是 2 类用户 Brian 的电话。因此 1 号时间片下,应输出新到的这通电
话,由于仍旧在处理 Andrew 的电话,所以在这个时间片不再输出开始处理 1 类用户 Andrew 电话。
当 2 号时间片开始时,没有电话生成。由于已经完成了 1 类用户 Andrew 电话,因此服务人员需要接听其他电
话,这时系统已有两通正在等待接听的电话,所以按照优先级原则,晚到的 2 类用户 Brian 的电话需要接听,因
此在这个时间片需要输出开始处理 2 类用户 Brian 电话。该电话时长为一个时间单元。
当 3 号时间片开始时,没有电话生成。由于已经完成了 2 类用户 Brian 电话,因此服务人员需要接听其他电话,
这时系统仅有 1 通正在等待接听的电话,4 类用户 Chris 的电话被接听,因此在这个时间片需要输出开始处理 4
类用户 Chris 电话。该电话时长为一个时间单元。
当 4 号时间片开始时,没有电话生成。也没有其他需要接听的电话,所以该时间片不需要输处其他信息。系
统模拟也结束了。
为清楚起见,在每一时间片开始,系统都提示如下信息:
Starting tick #<tick>
这里的<tick>
表示时间片编号,从 0 开始。某人电话生成时,输出格式如下:
Call from <Name> a Level<status> member
开始处理某人电话时,输出格式如下:
Answering call from <Name>
这里的<Name>
、<status>
与前面一致。
对于上面的存储离散时间的示例输入文件 sample.txt,程序运行后应输出如下信息(分割线中内容):
--------------------------------------------- 盘符> call < sample.txt <—注意这里使用了输入重定向,表示输入设备是文件,不是键盘
Starting tick #0
Call from Andrew a Level1 member
Call from Chris a Level4 member
Answering call from Andrew
Starting tick #1
Call from Brian a Level2 member
Starting tick #2
Answering call from Brian
Starting tick #3
Answering call from Chris
Starting tick #4
--------------------------------------------- 编写程序,按照上述要求完成离散事件的模拟任务。实现完后,可以变动 sample.txt 内容执行程序,检验程序功能
是否满足上面的要求,运行正常。
Process
具体思路我都写在注释里了,emmm.
Code
Dlist.h
#ifndef __DLIST_H__
#define __DLIST_H__
// Get a definition for NULL
#include <iostream>;
using namespace std;
class emptyList {
// OVERVIEW: an exception class
public:
emptyList() {}
};
template <typename T>
class Dlist {
// OVERVIEW: contains a double-ended list of Objects
public:
// Operational methods
bool isEmpty() const;
// EFFECTS: returns true if list is empty, false otherwise
void insertFront(T* o);
// MODIFIES this
// EFFECTS inserts o at the front of the list
void insertBack(T* o);
// MODIFIES this
// EFFECTS inserts o at the back of the list
T* removeFront();
// MODIFIES this
// EFFECTS removes and returns first object from non-empty list
// throws an instance of emptyList if empty
T* removeBack();
// MODIFIES this
// EFFECTS removes and returns last object from non-empty list
// throws an instance of emptyList if empty
// Maintenance methods
Dlist(); // constructor
Dlist(const Dlist& l); // copy constructor
Dlist& operator=(const Dlist& l); // assignment
~Dlist(); // destructor
private:
// A private type
struct node {
node* next;
node* prev;
T* o;
};
node* first; // The pointer to the first node (NULL if none)
node* last; // The pointer to the last node (NULL if none)
// Utility methods
void makeEmpty();
// EFFECT: called by constructors to establish empty list invariant
void removeAll();
// EFFECT: called by destructor/operator= to remove and destroy all list elements
void copyAll(const Dlist& l);
// EFFECT: called by copy constructor/operator= to copy elements
// from a source instance l to this instance
};
template<class T>
void Dlist<T>::insertFront(T* o)
{
node* temp = new node();
temp->o = o;
temp->prev = nullptr;
temp->next = first;
if (first)
first->prev = temp;
else
last = temp;
first = temp;
}
template<class T>
void Dlist<T>::insertBack(T* o) {
node* temp = new node;
temp->o = o;
temp->next = nullptr;
temp->prev = last;
if (last)
last->next = temp;
else
first = temp;
last = temp;
}
template<class T>
bool Dlist<T>::isEmpty() const {
return first == nullptr;
}
template<class T>
T* Dlist<T>::removeFront() {
if (first) {
node* temp = first;
first = first->next;
if (first)
first->prev = nullptr;
else {
first = nullptr;
last = nullptr;
}
return temp->o;
}
else {
try {
emptyList* e = new emptyList();
throw(e);
}
catch (emptyList * that) {
cout << "Not enough operands" << endl;
}
return nullptr;
}
}
template<class T>
T* Dlist<T>::removeBack() {
if (last) {
node* temp = last;
last = last->prev;
if (last)
last->next = nullptr;
else {
first = nullptr;
last = nullptr;
}
return temp->o;
}
else
{
try {
emptyList* e = new emptyList();
throw(e);
}
catch (emptyList * that) {
cout << "Not enough operands" << endl;
}
return nullptr;
}
}
template<class T>
Dlist<T>::Dlist() {
makeEmpty();
}
template<class T>
Dlist<T>::Dlist(const Dlist& l) {
copyAll(l);
}
template<class T>
Dlist<T>& Dlist<T>::operator=(const Dlist& l) // assignment
{
removeAll();
copyAll(l);
return *this;
}
template<class T>
Dlist<T>::~Dlist() {
removeAll();
}
template<class T>
void Dlist<T>::makeEmpty() {
first = nullptr;
last = nullptr;
}
template<class T>
void Dlist<T>::removeAll() {
node* p = first;
while (p) {
node* temp = p;
p = p->next;
delete temp;
}
}
template<class T>
void Dlist<T>::copyAll(const Dlist& l) {
if (l.first) {
//makeEmpty();
node* p = l.first;
node* q = new node;
first = q;
node* pq = nullptr;
while (p) {
q->o = p->o;
q->prev = pq;
pq = q;
if (!p->next)
{
last = q;
q->next = nullptr;
break;
}
q->next = new node;
q = q->next;
p = p->next;
}
}
}
#endif /* __DLIST_H__ */
main.cpp
#include<iostream>
#include<fstream>
#include<vector>
#include"Dlist.h"
using namespace std;
#define MAX 100000
struct tele
{
int timestamp, status, duration, id;
string name;
};
int n;
bool vis[MAX];//vis记录时间片
Dlist<tele>* list = new Dlist<tele>;
void infile() {//文件数据读取
ifstream inFile;
inFile.open("simple.txt");
if (inFile.fail())
cout << "simple.txt doesn't exist" << endl;
else
{
int i = 0;
inFile >> n;
while (!inFile.eof())
{
tele* temp = new tele;
inFile >> temp->timestamp >> temp->name >> temp->status >> temp->duration;
temp->id = i++;
list->insertBack(temp);//倒插入队列
}
inFile.close();
}
}
int main()
{
memset(vis, 0, sizeof(vis));
infile();
int cnt = 0, snum = n;//cnt为当前时间,snum为未处理电话
while (!list->isEmpty()) {//队列不空则继续循环
Dlist<tele>* ltemp = new Dlist<tele>;
cout << "Starting tick #" << cnt << endl;
int temptime = 0, tempi = 0, tempid = 0, minn = MAX, tempsort = 0;
do{
tempi++;//限制do-while循环不能超过未处理电话数目
tele* t = new tele;
t = list->removeFront();//为遍历只能删除,后面会再加回去
if (cnt == t->timestamp)//当前时间节点来电
cout << "Call from " << t->name << " a Level" << t->status << " member" << endl;
if (t->status < minn)//寻找优先级最高的来电
{
tempid = t->id;//id记录下来
minn = t->status;
}
ltemp->insertFront(t);//把刚刚删除的节点放入ltemp队列中,等待插回队列
temptime = t->timestamp;//时间限制循环
} while (temptime <= cnt && tempi < snum);
while (!ltemp->isEmpty()) {
tele* temp = new tele();
temp = ltemp->removeFront();
if (temp->id == tempid && !vis[cnt])//如果当前节点没有正在处理的电话,则处理优先级最高的来电(不用插回队列)
{
--snum;
for (int count = 0; count < temp->duration; count++)//来电持续时长
vis[temp->timestamp + count] = 1;
cout << "Answering call from " << temp->name << endl;
}
else
list->insertFront(temp);
}
cnt++;//时间向前走
}
cout << "Starting tick #" << cnt << endl;//最后输出一次
return 0;
}