【实验报告】 线性数据结构的实现与应用_双端队列_逆波兰式_呼叫中心_XAUAT_(原问题自杜克大学C++ Stacks and Queues and Lists)

附问题链接:

https://blog.csdn.net/weixin_43781565/article/details/106506822

求打赏求收藏求转发!

提供DOC资源

https://download.csdn.net/download/weixin_43781565/12490532

(审核后可供下载)

Peace and love

图片全部转存失败我真的很难受.....有需要评论吧

 

一. 实验目的

 

1. 掌握双端队列的双链表实现。

2. 掌握基于双端队列的栈的应用:逆波兰表达式求值。

3. 掌握基于双端队列的普通队列的应用:呼叫中心的离散事件模拟。

 

二. 实验要求、内容

 

1. 基于双链表实现双端队列的典型操作(判空、头插、头删、尾插、尾删、普通构造、拷贝构造、赋值运算符重载、析构),编写简单程序使用该双端队列,测试和调试程序。

    2. 基于双端队列的头插、头删操作,完成栈的应用:逆波兰表达式求值,测试和调试程序。

    3. 基于双端队列的头删、尾插操作,完成普通队列的应用:呼叫中心的离散事件模拟,测试和调试程序。

    4. 按要求撰写实验报告、录制程序运行以及讲解程序的视频。

 

三. 实验设备

 

计算机、Windows 操作系统、C++语言集成开发环境。

 

四. 实验原理(或程序框图)及步骤

    

1. 双端队列的双链表实现

 

链表(linked list)是一种物理存储单元上非连续、非顺序的存储结构,是通过链表中的指针链接实现的。链表由一系列结点组成,每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。而如果我们给链表的每一个结点都增加一对指针,并给予他们与原有结点相反的功能,我们就可以得到一个双端链表(double link list),或称为双端队列。

 

图4.1.1 双端链表(double link list)

 

对于双端队列,我们拥有4 种数据的操作:左端出队,右端入队,左端入队和右端出队,而在实验一中,我们就是要基于链表实现双端队列的“增删改查”以及相关的构造与重载。

插入元素对于链表来说,是通过更换指针所指的地址来实现元素的插入,在双端队列里也不例外。

我们将节点"ai-1"的后继节点改为"x";"x"的前继节点改为"ai-1",后继节点改为"ai";"ai"的前继节点改为"x",即完成了对双端队列的插入操作。

需要注意的是,操作①必须在操作③之前完成,否则可能会丢失前驱结点。

对于删除结点来说,与插入类似,是通过更换指针所指的地址来实现元素的删除。

 

我们要删除节点"ai",则需要将节点"ai-1"的后继节点改为"ai+1",将"ai+1"的前继节点改为"ai-1",即完成了对双端队列的删除操作。

而对于构造函数,我们则需要给每一个创建头结点与尾结点,表示两个指针;对于赋值运算符重载与拷贝构造函数的意义是一样的,我们设立一个copyAll()函数,进行两个队列的复制工作;于此同时,我们还设置了removeAll()函数,用来移除队列,isEmpty()函数用来返回队列是否已经不包含存储容量,用来辅助其他函数的功能实现以及后期的相关应用。

 

2. 逆波兰表达式求值

逆波兰表达式(Reverse Polish Notation)又称为后缀表达式,是波兰逻辑学家卢卡西维兹提出的一种表达式的表示方法, 是一种没有括号,并严格遵循“从左到右”运算的后缀式表达方法.我们平常使用的计算表达式大都是中缀表达式,如A+B*(C-D)-E*F,如图所示:

图4.2. A+B*(C-D)-E*F的二叉树表示

中缀表达式得名于它是由相应的语法树的中序遍历的结果得到的。上面的二叉树中序遍历的结果就是A+B*(C-D)-E*F。逆波兰式是由后序遍历的结果得到的上图的后缀表达式为:A B C D - * + E F * -

相对于计算机来说,后缀表达式的处理成本要比中缀表达式相比较低。所以我们本次的实验,需要应用1中的双端队列的部分功能,实现逆波兰式的算式读取分析与计算,并读出结果。

我们可以以3 4 + 5 × 6 -的计算为例:

  1. 从左至右扫描,将3和4压入堆栈;
  2. 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素,注意与前缀表达式做比较),计算出3+4的值,得7,再将7入栈;
  3. 将5入栈;
  4. 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
  5. 将6入栈;
  6. 最后是-运算符,计算出35-6的值,即29,由此得出最终结果。

所以经过分析,我们可以采用一个栈来实现计算,扫描表达式从左往右进行,如果扫描到数值,则压进辅助栈中,如果扫描到运算符,则从辅助栈中弹出两个数值参与运算,并将结果压进到栈中,当扫描表达式结束后,栈顶的数值就是表达式结果。我们需要利用双端队列,实现基本的栈的操作,如压栈(push),弾栈(pop),再加以适当的判断操作即可。

除此之外,为了满足实验的要求,还应加入判断函数,以对逆波兰式输入的内容进行判断,防止出现错误的数值或字符输入,导致程序崩溃。

 

  1.  呼叫中心的离散事件模拟

 

在实验的第三部分,我们需要在第1部分双端队列的基础上,模拟一个呼叫中心的客服电话系统,系统需要根据用户在不同的打进电话时间,不同的用户身份等级与不同的处理时长的情况下,合理的分配电话的接听与等待。基于要求的设定,我们需要将双链表的双端队列改造成为一个单链表的普通队列。

链表(list),是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。其中存储数据元素信息的域称作数据域(data),存储直接后继存储位置的域称为指针域(next)。指针域中存储的信息又称做指针或链。

与形成双端队列的双链表不同的是,单链表的每个结点仅有一个指针域,指向下一个结点,即为“单向”模式,较双链表来说随功能不如双链表完善,但节约空间资源,且符合我们本次实验“电话排队”的要求。

因为对于每个打进电话的用户来说,都需要记录他们的时间点(timestamp),姓名(Name),等级(status)和处理时间长度(duration),所以可以根据对应的需求建立客人类(Customer),并包含对应的字段进行对象创建,并应该包含插入队列和根据等级查找客人的操作。其次,实验要求从文件输入程序所需要的数据,我们需要创建文件对象并使用文件输入对应的数据。

根据实验要求,我们应该先读入总共模拟的电话数,为每一个级别创建一个队列,然后读入对应的字段,并进入第一个时间片,搜索最先且同时打进电话的用户,并根据等级选择最高的用户开始通话,并读取该用户电话接听所需时间片,开始处理,不断循环,与此同时在不同的时间片打进电话的用户,给予提示信息,直到最后一位用户电话接听所需时间片结束且没有电话接入,程序结束。

在程序中应使用if else结构判断各种的情况,并应该加入当前电话状态的判断,具体的程序细节在第五部分呈现。

 

五. 程序源代码

 

  1. 双端队列的双链表实现

包含文件数:3

文件名:DList.h, Dlist.cpp, 源.cpp

 

1) DList.h

  1. class emptyList
  2. {
  3.     // OVERVIEW: an exception class
  4. };

 

  1. template <class T>
  2. class Dlist
  3. {
  4.     // OVERVIEW: contains a double-ended list of Objects

 

  1. public:

 

  1.     // Operational methods

 

  1.     bool isEmpty() const;
  2.     // EFFECTS: returns true if list is empy, false otherwise

 

  1.     void insertFront(T* o);
  2.     // MODIFIES this
  3.     // EFFECTS inserts o at the front of the list

 

  1.     void insertBack(T* o);
  2.     // MODIFIES this
  3.     // EFFECTS inserts o at the back of the list

 

  1.     T* removeFront();
  2.     // MODIFIES this
  3.     // EFFECTS removes and returns first object from non-empty list
  4.     //         throws an instance of emptyList if empty

 

  1.     T* removeBack();
  2.     // MODIFIES this
  3.     // EFFECTS removes and returns last object from non-empty list
  4.     //         throws an instance of emptyList if empty

 

  1.     // Maintenance methods
  2.     Dlist();                                   // constructor
  3.     Dlist(const Dlist& l);                     // copy constructor
  4.     Dlist& operator=(const Dlist& l);          // assignment operator
  5.     ~Dlist();                                  // destructor

 

  1. private:
  2.     // A private type
  3.     struct node
  4.     {
  5.         node* next;
  6.         node* prev;
  7.         T* o;
  8.     };

 

  1.     node* first; // The pointer to the first node (NULL if none)
  2.     node* last;  // The pointer to the last node (NULL if none)

 

  1.     // Utility methods

 

  1.     void removeAll();
  2.     // EFFECT: called by destructor/operator= to remove and destroy
  3.     //         all list elements

 

  1.     void copyAll(const Dlist& l);
  2.     // EFFECT: called by copy constructor/operator= to copy elements
  3.     //         from a source instance l to this instance
  4. };

2) Dlist.cpp

  1. #include"Dlist.h"
  2. #include <cstdlib>
  3. #include<iostream>
  4.  
  5. using namespace std;
  6.  
  7. template<class T>
  8. bool Dlist<T> ::isEmpty() const {
  9.     return (first == NULL) && (last == NULL);
  10. }//如果列表为空,则返回true,否则返回false(判空)
  11.  
  12.  
  13. template<class T>
  14. void Dlist<T> ::insertFront(T* o) {
  15.     node* np = new node;
  16.     np->o = o;
  17.     np->next = first;
  18.     np->prev = NULL;
  19.  
  20.     if (!isEmpty()) {
  21.         first->prev = np;
  22.     }
  23.     else {
  24.         last = np;
  25.     }
  26.  
  27.     first = np;
  28.     return;
  29. }//在列表的前面插入o(头插)
  30.  
  31. template<class T>
  32. void Dlist<T> ::insertBack(T* o) {
  33.     node* np = new node;
  34.     np->o = o;
  35.     np->prev = last;
  36.     np->next = NULL;
  37.  
  38.     if (!isEmpty()) {
  39.         last->next = np;
  40.     }
  41.     else {
  42.         first = np;
  43.     }
  44.  
  45.     last = np;
  46.     return;
  47. }//在列表的后面插入o(尾插)
  48.  
  49. template<class T>
  50. T* Dlist<T> ::removeFront() {
  51.     if (isEmpty()) {
  52.         emptyList error;
  53.         throw error;
  54.     }
  55.  
  56.     node* victim = first;
  57.     first = victim->next;
  58.  
  59.     if (first == NULL) {
  60.         last = NULL;
  61.     }
  62.     else {
  63.         first->prev = NULL;
  64.     }
  65.  
  66.     T* o = victim->o;
  67.     delete victim;
  68.     return o;
  69. }   //从非空列表中删除并返回第一个对象(头删)
  70.     //如果为空则抛出emptyList的实例
  71.  
  72. template<class T>
  73. T* Dlist<T> ::removeBack() {
  74.     if (isEmpty()) {
  75.         emptyList error;
  76.         throw error;
  77.     }
  78.  
  79.     node* victim = last;
  80.     last = victim->prev;
  81.     if (last == NULL) {
  82.         first = NULL;
  83.     }
  84.     else {
  85.         last->next = NULL;
  86.     }
  87.  
  88.     T* o = victim->o;
  89.     delete victim;
  90.     return o;
  91. }//从非空列表中删除并返回最后一个对象(尾删)
  92.  //如果为空则抛出emptyList的实例
  93.  
  94. template<class T>
  95. Dlist<T> ::Dlist() {
  96.     first = NULL;
  97.     last = NULL;
  98. }//构造函数
  99.  
  100. template<class T>
  101. Dlist<T> ::Dlist(const Dlist& test_list) {
  102.     first = NULL;
  103.     last = NULL;
  104.     copyAll(test_list);
  105. }//拷贝构造函数
  106.  
  107. template<class T>
  108. Dlist<T>& Dlist<T> :: operator=(const Dlist& test_list) {
  109.     copyAll(test_list);
  110.     return *this;
  111. }//赋值运算符重载
  112.  
  113. template<class T>
  114. Dlist<T> :: ~Dlist() {
  115.     removeAll();
  116. }//析构函数
  117.  
  118. template<class T>
  119. void Dlist<T> ::removeAll() {
  120.     while (!isEmpty()) {
  121.         T* o = removeFront();
  122.         delete o;
  123.     }
  124.     return;
  125. }//由析构函数 / = 运算符重载 调用删除所有列表元素
  126.  
  127. template<class T>
  128. void Dlist<T> ::copyAll(const Dlist& test_list) {
  129.     removeAll();
  130.     node* np = test_list.first;
  131.  
  132.     while (np != NULL) {
  133.         T* o = new T(*np->o);
  134.         insertBack(o);
  135.         np = np->next;
  136.     }
  137.  
  138.     return;
  139. }
  140. //由拷贝构造函数/ = 运算符重载 调用复制元素
  141. //从源实例test_list到此实例

3) DataStructure_1_1.cpp

  1. #include <cstdlib>
  2. #include<iostream>
  3. #include"Dlist.cpp"
  4. using namespace std;
  5. int main(int argc, char* argv[])
  6. {
  7.    /* 示例程序:
  8.    Dlist<int> ilist;
  9.     int* ip = new int(3);
  10.     ilist.insertFront(ip);
  11.     ip = ilist.removeFront();
  12.     cout << *ip << endl;
  13.     delete ip;
  14.     return 0;
  15.     */

 

  1.     //自编程序:
  2.    cout << "前插13,15,17到test_list中并前删" << endl;
  3.     Dlist<int> test_list;
  4.     int* a = new int(13);
  5.     int* b = new int(15);
  6.     int* c = new int(17);
  7.     test_list.insertFront(a);
  8.     test_list.insertFront(b);
  9.     test_list.insertFront(c);
  10.     cout << endl << *test_list.removeFront() << endl;
  11.     cout << *test_list.removeFront() << endl;
  12.     cout << *test_list.removeFront() << endl;
  13.     cout << endl << "使用前插13,15,17到test_list中并尾删" << endl;
  14.     test_list.insertFront(a);
  15.     test_list.insertFront(b);
  16.     test_list.insertFront(c);
  17.     cout << endl << *test_list.removeBack() << endl;
  18.     cout << *test_list.removeBack() << endl;
  19.     cout << *test_list.removeBack() << endl;
  20.     cout << endl;
  21.     test_list.insertFront(a);
  22.     test_list.insertFront(b);
  23.     test_list.insertFront(c);
  24.     cout << "拷贝构造函数构造x" << endl;
  25.     Dlist<int> x(test_list);
  26.     cout << "x的尾删" << endl;
  27.     cout << *x.removeBack() << endl;
  28.     cout << "重载运算符y=test_list" << endl;
  29.     Dlist<int> y = test_list;
  30.     cout << "y尾删" << endl;
  31.     cout << *y.removeBack() << endl;
  32. }

 

 

2. 逆波兰表达式求值

包含文件数:3;

文件名:DList.h, Dlist.cpp, DataStructure_1_2.cpp;

备注:DList.h, Dlist.cpp与1中代码相同,为引用形式

 

DataStructure_1_2.cpp

  1. // DataStructure_1_2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
  2. //
  3. //软件1801 
  4. #include <iostream>
  5. #include <string>
  6. #include <string.h> 
  7. #include <cstdlib>
  8. #include "C:\Users\Edward\source\repos\DataStructe_1\Dlist.h"
  9. #include "C:\Users\Edward\source\repos\DataStructe_1\Dlist.cpp"

 

  1. using namespace std;

 

  1. bool isInteger(string str);
  2. //判断数字:
  3. //如果str仅由int组成,则返回true
  4. //否则返回false
  5. //如果str是以“ +”开头的int,则返回false

 

  1. int main() {

 

  1. Dlist<int> RPNStack; // 开辟堆栈
  2. string inputString = "";
  3. int* tempIntPtr = NULL;

 

  1. cin >> inputString;

 

  1. while (1) {
  2. if (inputString == "+") {
  3. //加法运算
  4. int* tempOperandPtr1 = NULL;
  5. int* tempOperandPtr2 = NULL;
  6. if (!RPNStack.isEmpty()) {
  7. tempOperandPtr1 = RPNStack.removeFront();
  8. if (!RPNStack.isEmpty()) {
  9. tempOperandPtr2 = RPNStack.removeFront();
  10. // Ptr1保存总和值
  11. *tempOperandPtr1 = *tempOperandPtr1 + *tempOperandPtr2;
  12. RPNStack.insertFront(tempOperandPtr1);
  13. tempOperandPtr1 = NULL;
  14. delete tempOperandPtr2;
  15. }
  16. else { //在第二次弹栈之前栈为空
  17. RPNStack.insertFront(tempOperandPtr1);
  18. tempOperandPtr1 = NULL;
  19. cout << "Not enough operands" << endl;
  20. //然后进入下一个输入
  21. }
  22. }
  23. else { //在第一次弹栈之前栈为空
  24. cout << "Not enough operands" << endl;
  25. //然后进入下一个输入
  26. }
  27. }
  28. else if (inputString == "-") {
  29. //减法运算
  30. int* tempOperandPtr1 = NULL;
  31. int* tempOperandPtr2 = NULL;
  32. if (!RPNStack.isEmpty()) {
  33. tempOperandPtr1 = RPNStack.removeFront();
  34. if (!RPNStack.isEmpty()) {
  35. tempOperandPtr2 = RPNStack.removeFront();
  36. // Ptr1保留差值
  37. *tempOperandPtr1 = *tempOperandPtr2 - *tempOperandPtr1;
  38. RPNStack.insertFront(tempOperandPtr1);
  39. tempOperandPtr1 = NULL;
  40. delete tempOperandPtr2;
  41. }
  42. else { //在第二次弹栈之前栈为空
  43. RPNStack.insertFront(tempOperandPtr1);
  44. tempOperandPtr1 = NULL;
  45. cout << "Not enough operands" << endl;
  46. //然后进入下一个输入
  47. }
  48. }
  49. else { //在第一次弹栈之前栈为空
  50. cout << "Not enough operands" << endl;
  51. //然后进入下一个输入
  52. }
  53. }
  54. else if (inputString == "*") {
  55. //乘法运算
  56. int* tempOperandPtr1 = NULL;
  57. int* tempOperandPtr2 = NULL;
  58. if (!RPNStack.isEmpty()) {
  59. tempOperandPtr1 = RPNStack.removeFront();
  60. if (!RPNStack.isEmpty()) {
  61. tempOperandPtr2 = RPNStack.removeFront();
  62. // Ptr1保留乘积
  63. *tempOperandPtr1 = (*tempOperandPtr1) * (*tempOperandPtr2);
  64. RPNStack.insertFront(tempOperandPtr1);
  65. tempOperandPtr1 = NULL;
  66. delete tempOperandPtr2;
  67. }
  68. else { //在第二次弹栈之前栈为空
  69. RPNStack.insertFront(tempOperandPtr1);
  70. tempOperandPtr1 = NULL;
  71. cout << "Not enough operands" << endl;
  72. //然后进入下一个输入
  73. }
  74. }
  75. else { //在第一次弹栈之前栈为空
  76. cout << "Not enough operands" << endl;
  77. //然后进入下一个输入
  78. }
  79. }
  80. else if (inputString == "/") {
  81. //除法运算
  82. int* tempOperandPtr1 = NULL;
  83. int* tempOperandPtr2 = NULL;
  84. if (!RPNStack.isEmpty()) {
  85. tempOperandPtr1 = RPNStack.removeFront();

 

  1. if (RPNStack.isEmpty()) {
  2. //在第二次移除之前堆叠为空
  3. RPNStack.insertFront(tempOperandPtr1);
  4. tempOperandPtr1 = NULL;
  5. cout << "Not enough operands" << endl;
  6. //然后进入下一个输入
  7. }
  8. else if (*tempOperandPtr1 == 0) {
  9. //无法除以0,将优先级降低为不足操作数
  10. RPNStack.insertFront(tempOperandPtr1);
  11. tempOperandPtr1 = NULL;
  12. cout << "Divide by zero" << endl;
  13. //然后进入下一个输入
  14. }
  15. else {
  16. tempOperandPtr2 = RPNStack.removeFront();
  17. //Ptr1保留除法值
  18. *tempOperandPtr1 = (*tempOperandPtr2) / (*tempOperandPtr1);
  19. RPNStack.insertFront(tempOperandPtr1);
  20. tempOperandPtr1 = NULL;
  21. delete tempOperandPtr2;
  22. }
  23. }
  24. else { //第一次删除之前堆栈为空
  25. cout << "Not enough operands" << endl;
  26. //然后进入下一个输入
  27. }
  28. }
  29. else if (inputString == "n") {
  30. //求相反数
  31. if (!RPNStack.isEmpty()) {
  32. tempIntPtr = RPNStack.removeFront();
  33. *tempIntPtr = (*tempIntPtr) * (-1);
  34. RPNStack.insertFront(tempIntPtr);
  35. tempIntPtr = NULL;
  36. }
  37. else { //在弹栈之前栈为空
  38. cout << "Not enough operands" << endl;
  39. //然后进入下一个输入
  40. }
  41. }
  42. else if (inputString == "d") {
  43. //复制操作
  44. if (!RPNStack.isEmpty()) {
  45. int* tempOriginalPtr;
  46. tempOriginalPtr = RPNStack.removeFront();
  47. int* tempDuplicatePtr = new int(*tempOriginalPtr);
  48. RPNStack.insertFront(tempOriginalPtr);
  49. RPNStack.insertFront(tempDuplicatePtr);
  50. tempOriginalPtr = NULL;
  51. tempDuplicatePtr = NULL;
  52. }
  53. else { //在第一次弹栈之前栈为空
  54. cout << "Not enough operands" << endl;
  55. //然后进入下一个输入
  56. }
  57. }
  58. else if (inputString == "r") {
  59. //反向操作,栈顶元素与次栈顶元素交换次序
  60. int* tempOperandPtr1 = NULL;
  61. int* tempOperandPtr2 = NULL;
  62. if (!RPNStack.isEmpty()) {
  63. tempOperandPtr1 = RPNStack.removeFront();
  64. if (!RPNStack.isEmpty()) {
  65. tempOperandPtr2 = RPNStack.removeFront();
  66. //首先提取Ptr1
  67. RPNStack.insertFront(tempOperandPtr1);
  68. RPNStack.insertFront(tempOperandPtr2);
  69. tempOperandPtr1 = NULL;
  70. tempOperandPtr2 = NULL;
  71. }
  72. else { //在第二次弹栈之前栈为空
  73. RPNStack.insertFront(tempOperandPtr1);
  74. tempOperandPtr1 = NULL;
  75. cout << "Not enough operands" << endl;
  76. //然后进入下一个输入
  77. }
  78. }
  79. else { //在第一次弹栈之前栈为空
  80. cout << "Not enough operands" << endl;
  81. //然后进入下一个输入
  82. }
  83. }
  84. else if (inputString == "p") {
  85. //打印操作
  86. if (!RPNStack.isEmpty()) {
  87. tempIntPtr = RPNStack.removeFront();
  88. cout << (*tempIntPtr) << endl;
  89. RPNStack.insertFront(tempIntPtr);
  90. tempIntPtr = NULL;
  91. }
  92. else { //在第一次弹栈之前栈为空
  93. cout << "Not enough operands" << endl;
  94. //然后进入下一个输入
  95. }
  96. }
  97. else if (inputString == "c") {
  98. //清除所有元素
  99. while (!RPNStack.isEmpty()) {
  100. int* tempClearPtr;
  101. tempClearPtr = RPNStack.removeFront();
  102. delete tempClearPtr;
  103. }
  104. }
  105. else if (inputString == "a") {
  106. //打印所有元素
  107. Dlist<int> printRPNStack(RPNStack);

 

  1. while (!printRPNStack.isEmpty()) {
  2. int* tempPrintPtr;
  3. tempPrintPtr = printRPNStack.removeFront();
  4. cout << (*tempPrintPtr) << " ";
  5. delete tempPrintPtr;
  6. }
  7. cout << endl;

 

  1. //  printRPNStack的析构函数将解决内存泄漏风险(现在应该没有)
  2. }
  3. else if (inputString == "q") {
  4. //退出操作
  5. break;
  6. //内存泄漏风险将由析构函数处理
  7. }
  8. else if (isInteger(inputString)) {
  9. //将int数字推入堆栈
  10. tempIntPtr = new int(atoi(inputString.c_str()));
  11. //atoi(ascii to integer)把字符串转换成整型数
  12. RPNStack.insertFront(tempIntPtr);
  13. tempIntPtr = NULL;
  14. }
  15. else {
  16. //输入无效
  17. cout << "Bad input" << endl;
  18. }
  19. //继续下一个输入
  20. cin >> inputString;
  21. }
  22. return 0;
  23. }

 

  1. bool isInteger(string str) {
  2. const char* C_String = str.c_str();
  3. //将C++的string转化为C的字符串数组
  4. unsigned long length = strlen(C_String);

 

  1. if (length == 0) {
  2. return false;
  3. }
  4. else if (length == 1) {
  5. return isdigit(C_String[0]);
  6. //用来判断一个字符是否是数字
  7. //返回值为真表示是数字,假表示不是数字
  8. }
  9. else { //C_String至少有两个字符
  10. if ((isdigit(*C_String)) || (*C_String == '-')) {
  11. //第一个字符为十进制数字或'-'
  12. //从第二个字符开始
  13. for (unsigned long index = 1; index < length; index++) {
  14. if (!isdigit(C_String[index])) {
  15. return false;
  16. }
  17. //如果C_String [index]是数字,则继续检查
  18. }
  19. //所有数字通过检查
  20. return true;
  21. }
  22. else {
  23. //第一个字符既不是十进制数字也不是'-'
  24. return false;
  25. }
  26. }
  27. }

 

  1. 呼叫中心的离散事件模拟

包含文件数:3;

文件名:DList.h, Dlist.cpp, DataStructure_1_3.cpp;

备注:DList.h, Dlist.cpp与1中代码相同,为引用形式

 

DataStructure_1_3.cpp

  1. #include <iostream>
  2. #include <string>
  3. #include <cstdlib>
  4. #include <fstream>
  5. #include "C:\Users\Edward\source\repos\DataStructe_1\Dlist.h"
  6. #include "C:\Users\Edward\source\repos\DataStructe_1\Dlist.cpp"
  7. //软件1801 
  8. using namespace std;
  9.  
  10. struct callEvent {
  11. int callTimeStamp; //该电话的拨入时间,非负整数
  12. string callerName; //用户姓名
  13. int callerStatus;  //用户的等级,1-4
  14. int callDuration;  //需要持续的时间片长度,正整数
  15. };
  16.  
  17. enum status {
  18. LEVEL1, LEVEL2, LEVEL3, LEVEL4
  19. };
  20.  
  21. status returnStatusEnum(int statusString);
  22. //返回对应的状态枚举
  23.  
  24. int main() {
  25.  
  26. int remainingBusyTime = 0;
  27. int remainingCallNum = 0;
  28. int nextCallTimeStamp = 0;
  29. int tickTok = 0;
  30. callEvent* tempCallPtr = NULL;
  31.  
  32. Dlist<callEvent> Level1Quene;
  33. Dlist<callEvent> Level2Quene;
  34. Dlist<callEvent> Level3Quene;
  35. Dlist<callEvent> Level4Quene;
  36. // 所有队列前删后插
  37. ifstream infile;
  38. infile.open("sample.txt");
  39. infile >> remainingCallNum;
  40.  
  41. if (remainingCallNum > 0) {
  42. infile >> nextCallTimeStamp;
  43. }
  44. else {
  45. cerr << "Unexpected total call number." << endl;
  46. }
  47.  
  48. //每个时间片进行一次循环
  49. while (1) {
  50. cout << "Starting tick #" << tickTok << endl;
  51.  
  52. if ((Level1Quene.isEmpty()) && (Level2Quene.isEmpty()) && (Level3Quene.isEmpty()) && (Level4Quene.isEmpty()) && (remainingBusyTime == 0) && (remainingCallNum == 0)) {
  53. break;
  54. }
  55. else { //仍在通话处理接听,完成处理并排队清除
  56. // 1.搜索呼入匹配时间片
  57. while (nextCallTimeStamp == tickTok) {
  58. // 1.1建立一个结构来保存通话信息
  59. tempCallPtr = new callEvent;
  60. tempCallPtr->callTimeStamp = nextCallTimeStamp;
  61. infile >> tempCallPtr->callerName
  62. >> tempCallPtr->callerStatus
  63. >> tempCallPtr->callDuration;
  64. remainingCallNum--;
  65. // 1.2更新nextCallTimeStamp
  66. if (remainingCallNum > 0) {
  67. infile >> nextCallTimeStamp;
  68. }
  69. else {
  70. nextCallTimeStamp = -1;
  71. //tickTok不会等于-1
  72. //不会进入while循环
  73. }
  74. // 1.3宣布呼入
  75. //例如“来自Andrew的level1 电话”
  76. cout << "Call from "
  77. << tempCallPtr->callerName
  78. << " a Level"
  79. << tempCallPtr->callerStatus
  80. << " member" << endl;
  81. // 1.4 将通话排队
  82. switch (returnStatusEnum(tempCallPtr->callerStatus)) {
  83. case LEVEL1:
  84. Level1Quene.insertBack(tempCallPtr);
  85. break;
  86. case LEVEL2:
  87. Level2Quene.insertBack(tempCallPtr);
  88. break;
  89. case LEVEL3:
  90. Level3Quene.insertBack(tempCallPtr);
  91. break;
  92. case LEVEL4:
  93. Level4Quene.insertBack(tempCallPtr);
  94. break;
  95. default:
  96. cerr << "Invalid status enum for caller "
  97. << tempCallPtr->callerName
  98. << " with status "
  99. << tempCallPtr->callerStatus
  100. << endl;
  101. tempCallPtr->callerName = "我是错误等级"; 
  102. //只是为了避免内存泄漏
  103. Level1Quene.insertBack(tempCallPtr);
  104. break;
  105. }
  106. tempCallPtr = NULL;
  107. }
  108.  
  109. // 2.结束通话或使另一个通话出队
  110. if (remainingBusyTime != 0) {
  111. // 2.1当前通话未完成
  112. remainingBusyTime--;
  113. }
  114. else {
  115. //接线员空闲
  116. // 2.2 从级别1开始从队列接听下一个呼叫
  117. if (!Level1Quene.isEmpty()) {
  118. //接听level1用户的电话
  119. callEvent* tempAnswerPtr;
  120. tempAnswerPtr = Level1Quene.removeFront();
  121. cout << "Answering call from "
  122. << tempAnswerPtr->callerName
  123. << endl;
  124. remainingBusyTime = tempAnswerPtr->callDuration - 1;
  125. delete tempAnswerPtr;
  126. }
  127. else if (!Level2Quene.isEmpty()) {
  128. //接听Level2用户的电话
  129. callEvent* tempAnswerPtr;
  130. tempAnswerPtr = Level2Quene.removeFront();
  131. cout << "Answering call from "
  132. << tempAnswerPtr->callerName
  133. << endl;
  134. remainingBusyTime = tempAnswerPtr->callDuration - 1;
  135. delete tempAnswerPtr;
  136. }
  137. else if (!Level3Quene.isEmpty()) {
  138. //接听level3用户的电话
  139. callEvent* tempAnswerPtr;
  140. tempAnswerPtr = Level3Quene.removeFront();
  141. cout << "Answering call from "
  142. << tempAnswerPtr->callerName
  143. << endl;
  144. remainingBusyTime = tempAnswerPtr->callDuration - 1;
  145. delete tempAnswerPtr;
  146. }
  147. else if (!Level4Quene.isEmpty()) {
  148. //接听Level4用户的电话
  149. callEvent* tempAnswerPtr;
  150. tempAnswerPtr = Level4Quene.removeFront();
  151. cout << "Answering call from "
  152. << tempAnswerPtr->callerName
  153. << endl;
  154. remainingBusyTime = tempAnswerPtr->callDuration - 1;
  155. delete tempAnswerPtr;
  156. }
  157. //其他:如果所有队列都为空,则滚动到下一个时间点
  158. } // “ if(remainingBusyTime!= 0)”中else的结尾 
  159. } // else from“if (time to exit while loop)”的结尾 
  160.  
  161. tickTok++;
  162. } //“ while(1)”的结尾
  163.  
  164. return 0;
  165. }
  166.  
  167. status returnStatusEnum(int statusString) {
  168. if (statusString == 1) {
  169. return LEVEL1;
  170. }
  171. else if (statusString == 2) {
  172. return LEVEL2;
  173. }
  174. else if (statusString == 3) {
  175. return LEVEL3;
  176. }
  177. else if (statusString == 4) {
  178. return LEVEL4;
  179. }
  180. else {
  181. return LEVEL1; // LEVEL1 == 0
  182. }
  183. }//返回对应的状态枚举

 

六. 实验数据、结果分析

 

1. 运行结果

 

1)双端队列的双链表实现

 

 

 

 

 

图6.1.1 示例程序运行结果

 


图6.1.2 自测程序运行结果

 

 

  1. 逆波兰表达式求值

 

图6.2 示例程序运行结果

 

 

3)呼叫中心的离散事件模拟

 

 

图6.3 示例程序运行结果

 

2. 结果分析

 

  1. 双端队列的双链表实现

在双链表的实现测试中,主要是对class Dlist中的相关函数进行测试,因此在main()函数的测试过程中除运行示例测试程序之外,还重新设置了新队列,并运用了插入,删除,拷贝构造与运算符重载等相关函数对Dlist进行测试,经测试程序能够正确运行,并打印出了相关的数据,符合要求。

 

  1. 逆波兰表达式求值

在逆波兰式表达式程序的测试中,运用示例程序进行测试,主要是测试程序在利用之前双端列表的情况下,改进后的进栈与弾栈操作是否符合相关的要求,能否计算出对应算式正确的值;并且检测程序是否实现了要求中的功能,如“输入错误”,“算式错误”,取相反数与按要求退出等,经测试程序能够正确运行,并计算出了示例程序中的相关算式结果,同时实现了相关的特定功能,符合要求。

 

  1. 呼叫中心的离散事件模拟

在呼叫中心模拟程序的测试中,运用示例文本文件sample.txt进行测试,主要是测试程序能否按照相关的要求,处理好不同时间与不同等级的用户来电情况,涉及的主要内容是队列的操作,如头插尾插等。分别输入总电话个数与不同等级下,同一时间与不同时间接入的电话,以测试程序是否能够按照预期的操作呈现最终的接听结果。经测试程序能够正确运行,并得出了对所有用户的操作情况,与实验的预期结果相同,符合要求。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值