目录
一、课程设计题目与要求
1、题目内容
2、题目要求
二、需求分析
1、总体功能需求
2、功能需求
3、软件开发平台需求
4、输入输出要求
三、设计
1、设计思想
1、数据结构设计
2、算法设计
2、设计表示:
1、函数调用关系图
2、函数接口规格说明
3、详细设计
四、调试分析
1、遇到主要的问题:
2、程序的时空复杂度分析:
3、经验体会:
五、用户手册
六、测试数据及测试结果
模拟某校九层教学楼的电梯系统。该楼有一个自动电梯,能在每层停留,其中第一层是大楼的进出层,即是电梯的“本垒层”,电梯“空闲”时,将来到该层候命。
电梯一共有七个状态,即正在开门(Opening)、已开门(Opened)、正在关门(Closing)、
已关门(Closed)、等待(Waiting)、移动(Moving)、减速(Decelerate)。
乘客可随机地进出于任何层。对每个人来说,他有一个能容忍的最长等待时间,一旦等候电梯时间过长,他将放弃。
模拟时钟从 0 开始,时间单位为 0.1 秒。人和电梯的各种动作均要消耗一定的时间单位(简记为 t),比如:
有人进出时,电梯每隔 40t 测试一次,若无人进出,则关门;
关门和开门各需要 20t;
每个人进出电梯均需要 25t;
电梯加速需要 15t;
上升时,每一层需要 51t,减速需要 14t;
下降时,每一层需要 61t,减速需要 23t;
如果电梯在某层静止时间超过 300t,则驶回 1 层候命。
基本:按时序显示系统状态的变化过程,即发生的全部人和电梯的动作序列。
扩展:实现电梯模拟的可视化界面。
该作品将实现一个模拟电梯,在界面上显示出电梯系统状态的变化过程,即发生的全部人和电梯的动作序列,对于乘客而言,动作包括等待电梯到来、进出电梯以及由于等待时间过长而离开电梯,对于电梯而言,动作包括电梯的加减速、上升与下降、开门与关门以及由于在某一层停留时间过长而驶回1层。其中要求乘客的产生是随机的,电梯有一定的载荷量,当超过载荷量的时候,电梯外乘客无法进入。
能够模拟出正常电梯的行为以及状态,能够计算并打印出当前时间电梯的行为是必要的
开发者开发的软件要求能够正常运行在Windows平台,且具有一定的平台兼容性.。为保证软件的上下兼容性,开发者应选择通用的开发工具的来进行开发,目前的开发软件平台为Visual Studio 2016。
该系统无需对其进行输入,用户只需运行,乘客的产生以及各信息由程序随机产生;
系统的输出为电梯系统状态的变化时间过程以及各乘客的动作序列过程,并打印出当前时间,如:
乘客1想做电梯,来自第9楼,去第2楼 现在时间:483
电梯准备去9楼 电梯经过3楼 现在时间:287
主要存储结构为类和链表;
电梯内的乘客和电梯外等待的乘客分别由两个链表存储,使用链表存储能够更容易地对乘客进行出入操作,并且可以帮助,当电梯在未超载的前提下,到达某楼层,满足可进电梯条件之后,将该乘客从等待链表中删去,又加入到电梯内乘客的链表中。
乘客和电梯封装成类,其中乘客类的属性包括了乘客的基本信息,包括等待时间、所来和所去楼层以及唯一编号;
电梯类的属性包括电梯从开始运行的时间、存储电梯内外的乘客的两个列表、电梯当前状态以及处于当前状态的时间、上次和当前以及目的楼层、现在电梯运行方向等。其方法包括自定义构造函数、随机产生乘客、主时间函数、乘客进出电梯函数、乘客离开电梯函数、用户因为等待时间过长离开、电梯判断可关门函数、电梯返回一楼函数等;
值得注意的是这里无论是电梯的状态还是乘客的状态都是枚举类型,好处是方便直观。
该系统可分为产生乘客、乘客进出电梯模块、电梯关门及运动、回到一楼、目的楼层计算五个模块,模拟时钟的运行依次照着这五个模块的次序而运转,接下来会详细介绍这五个模块:
本模块使用随机函数产生乘客,经过测试可得到,平均每100t产生一名乘客较合理,因此,我们对于每1t产生一个随机数,并对结果模上100,若为0则产生乘客,反之不成立。当确定产生乘客时,随机产生乘客的其他信息,譬如乘客当前所在楼层和目的楼层,对其状态设为等待电梯状态并开始计时。
调用此模块之前,需要对当前是否能够开门进行判断,判断可行之后,延时20t来表示开门的20t,此后,再对人进入电梯以及离开电梯进行操作,并将当前楼层修改为之前的目的楼层。
调用此模块之前,需要对当前是否能够关门进行判断,与上一模块不同的是确定关门之后,每40t判断一次,而不是每时每刻都在判断,关门之后,将当前状态设为waiting或上行、下行,而当前状态时间设为0。
该模块相对而言较简单,如果电梯在某层静止时间超过 300t,则驶回 1 层候命,判断可行时,将目的楼层设为1。
该模块首先会根据当前电梯运转方向、电梯外乘客所在楼层、电梯内乘客的目的楼层来判断是否继续该方向的运转,如果满足,选择最靠近当前楼层的楼层为目的楼层,若不满足,比如,之前电梯方向为上,但是电梯没有想去更高楼层的乘客,电梯外也没有更高楼层的乘客在等侯,这时候,电梯应该考虑向下运转,之后,我们再根据计算结果到达目的楼层。
下图为主程序的流程图:
Elevator()
说 明:重写电梯类的构造函数,初始化电梯的所有参数。
参 数:无
返 回 值:无
void Random_Man();
说 明:平均每100t随机产生一名乘客,并在该函数中实现乘客的信息随机产生,除此外,还有判断电梯外乘客是否离开,以及通过乘客决定目的楼层。
参 数:无
返 回 值:无
void Time_();
说 明:电梯的模拟时钟函数,作为主函数中循环调用的函数,并在其内部一次调用其它模块。
参 数:无
返 回 值:无
void entryElevator();
说 明:乘客进入电梯函数 : 在电梯开门后,将满足进入电梯的乘客信息从等待链表中删除,并添加到电梯内部乘客链表中。
参 数:无
返 回 值:无
void leaveElevator();
说 明:乘客离开电梯函数 : 在电梯开门后判断电梯内的乘客是否满足离开电梯的条件,将其信息删去。
参 数:无
返 回 值:无
int canBackToOne();
说 明:判断电梯是否满足因为等待时间过长而回到一楼的条件。
参 数:无
值 |
意义 |
0 |
不满足自动返回一楼的条件 |
1 |
满足自动返回一楼的条件 |
void manLeave();
说 明:对电梯外的乘客依次进行判断是否由于等待时间过长而停止等待
参 数:无
返 回 值:无
int isPause();
说 明:通过计算来判断当前电梯是否已到达目的楼层。
参 数:无
返 回 值:
值 |
意义 |
0 |
电梯未到目的楼层 |
1 |
电梯已到目的楼层 |
void Pause();
说 明:当电梯到达到目的楼层之后进行的一系列操作,包括开门、乘客的进入与离开。
参 数:无
返 回 值:无
int pre_Moving();
说 明:计算电梯当前的目的楼层。
参 数:无
返 回 值:返回当前电梯的目的楼层。
int canClose();
说 明:判断电梯当前是否可以进行关门操作。
参 数:无
返 回 值:
值 |
意义 |
0 |
电梯不可关门 |
1 |
电梯可关门 |
void Close();
说 明:当电梯准备关门之后进行的一系列操作,包括关门,以及电梯的方向决定。
参 数:无
返 回 值:无
int UpStairs();
说 明:计算得到电梯内乘客所想去的最高楼层。
参 数:无
返 回 值:返回电梯内乘客所想去的最高楼层。
int DownStairs();
说 明:计算得到电梯内乘客所想去的最低楼层。
参 数:无
返 回 值:计算得到电梯内乘客所想去的最低楼层。
1、电梯状态
/**
* 将电梯的状态设为枚举类型,简单直观
*/
enum Status {
Opening = 1, Opend, Closing, Closed, Waiting, Down_Moving,Up_Moving, Decelerate, Accelerate
};
2、乘客类:
/**
* 定义一个乘客的所有信息
*/
class Man {
public:
int num;
int from;
int to; //去哪里
int Time; //等待时间
Status_Man Status; //只有等待和不等待
};
3、电梯类:
/**
* 自定义的一个模拟电梯类
*/
数据成员:
public:
list
list
int time; //电梯已经运行的时间
int now_Floor; //上次电梯开门的楼层
int next_Floor; //电梯的目的楼层
Status now_Status; //电梯当前状态
int before; // 1:之前是向上的 0:之前向下
int parm_Floor; //当前所处楼层
int now_Status_Time; //当前状态已花时间
1) 在使用STL对链表里面的元素进行删除时,总是造成不可预期的错误,因为erase之后,链表更新,迭代器可能发生错误,之前在这个问题上停留了很久,最终通过阅读《STL源码剖析》找到了解决方案,先判断迭代器是否为最后一个元素,若不是,则使用erase(),若是,则使用pop_back()。
2) 对该模拟电梯进行设计的时候,因为电梯需要逻辑判断和行为实施同时进行,比如需要在电梯上下运行的同时,不能影响乘客的产生,同时还需要判断是否到达目的楼层,一开始所想的是使用多线程编程,但是C++对多线程很不友好,需要对windows底层进行编程,比较麻烦,因此,最后通过sleep()暂时休眠进程来对每一个t进行实际操作。
3) 在计算下一个目的楼层的时候,通过pre_Moving()计算之后的结果总是与实际结果不一样,具体表现在当电梯某一楼层时,突然显示到了第14层,通过单步断点,最后发现是计算当前楼层发生了逻辑错误,修改代码之后,将当前楼层加入到类的属性之中,防止接下来的代码编写出现类似问题。
4) 显示电梯和用户的动作序列时,之前是将其直接输出,最后显示的太过混乱,电梯行为和用户的行为序列互相混淆,因为没有使用图形化界面,最后解决办法是将电梯的行为输出到屏幕左边,乘客的行为输出到右边,中间显示电梯的时间,同时在关于给每一个人一个标识的时候,为了达到标识与记录两种功能,最后选择使用全局数字序号,因为它简洁,能够产生的标识多而且相比较而言更容易实现。
该系统的运行时间是无穷的,当开始启动之后,电梯的每时每刻都在运行或者等待操作,因此在讨论复杂度的时候是对每一个时间t所要完成的任务作复杂度分析,对于本程序,使用最多的算法是对链表的操作,主要是插入和删除操作,因为插入操作是直接在链表的头指针直接插入的时空复杂度均为O(1),因此最高的时间复杂度就是对链表的删除操作,其时间复杂度为O(n),空间复杂度为O(1),其中n为链表的长度。对于其他操作,如计算目的楼层时,需要对链表中的元素进行遍历,通过分析,时间复杂度为O(n),空间复杂度为O(1),实际情况下,由于每t都有可能随机产生1名乘客,但是乘客的最大等待时间是300t,因此电梯外乘客的链表不会超过300,而电梯内乘客链表由于电梯负载限制最多容纳13人。
1) 我认为使用多线程编程能使得该系统更简单: 用虚拟时钟,自己设置一个相对时间,每进行一个动作就将这个动作所用的时间加到一个全局变量中,并且每进行一个动作就将该动作的执行内容输出,通过并行操作之后,实际中的t和编码之后的t是一样的,但是在该系统之中,题目所要求得t和该系统的t是有所不同的,但是C++多线程的处理过程很让人费解,因为对于本道题我更倾向于使用Java,因为对Java的多线程有比较深的理解,可以将本道题没有使用多线程的缺陷运用上去。
2) 理解分析问题的能力得到提高。设计一个应用程序关键是对要求做最准确的把握,也就是说弄清楚需求分析是很重要的。这道题刚开始看,很难理解这道题要达到的目的是什么,如何通过模拟时钟来告知各模块应执行什么操作,同时又要对乘客的进入进行操作,这之间的过程很让人费解,经过仔细的多次读题后,画了个草图,才理清其中的思路。所以,通过这道题,大大提高了我的理解分析问题能力。
1.打开文件
windows环境下双击执行文件 zzz_eleva.exe。
2.运行:
(1)界面左边显示的是电梯的动作序列,比如当前楼层、目标楼层和当前方向,或者是电梯的开门、关门、加速和减速等等;
(2)界面右边显示的是乘客的动作序列,包括乘客的随机产生成功、乘客因等待时间过长而离去、乘客进入或离开电梯;
(3)界面中间显示的是当前电梯运行的时间,单位是t。
3.退出:
在任意时刻,操作者都可点击右上角的“X”来退出电梯模拟。
测试输入:
数据是程序随机生成,包括产生乘客的时间和楼层信息:
电梯时间 |
乘客编号 |
来自楼层 |
目的楼层 |
4t |
乘客1 |
9 |
2 |
155t |
乘客2 |
3 |
7 |
183t |
乘客3 |
9 |
2 |
199t |
乘客4 |
3 |
5 |
267t |
乘客5 |
9 |
7 |
452t |
乘客6 |
7 |
2 |
504t |
乘客7 |
2 |
5 |
… |
… |
… |
… |
测试目的:
1)电梯是否能够正常运行;
2)电梯时间是否正常。
3)乘客是否能够在等待时间内乘坐电梯,并在目的楼层离开电梯;
正确输出:
现在时间:4 乘客1想做电梯,来自第9楼,去第2楼
电梯准备去9楼 电梯经过1楼 ↑ 现在时间:19
电梯准备去9楼 电梯经过2楼 ↑ 现在时间:70
电梯准备去9楼 电梯经过3楼 ↑ 现在时间:121
现在时间:155 乘客2想做电梯,来自第3楼,去第7楼
电梯准备去9楼 电梯经过4楼 ↑ 现在时间:172
现在时间:183 乘客3想做电梯,来自第9楼,去第2楼
现在时间:199 乘客4想做电梯,来自第3楼,去第5楼
电梯准备去9楼 电梯经过5楼 ↑ 现在时间:223
现在时间:267 乘客5想做电梯,来自第9楼,去第7楼
电梯准备去9楼 电梯经过6楼 ↑ 现在时间:274
现在时间:300 1号乘客等待时间过长离开
电梯准备去9楼 电梯经过7楼 ↑ 现在时间:325
电梯准备去9楼 电梯经过8楼 ↑ 现在时间:376
电梯准备去9楼 电梯经过9楼 ↑ 现在时间:427
现在时间:441
电梯已到9楼
1电梯在开门 现在时间:441
现在时间:452 乘客6想做电梯,来自第7楼,去第2楼
现在楼层在9 现在时间:461
现在时间:470
电梯已到9楼
1电梯在开门 现在时间:470
现在时间:490 5号乘客从9楼进入电梯,想去7楼
电梯进人ing
现在时间:504 乘客7想做电梯,来自第2楼,去第5楼
现在时间:504 2号乘客等待时间过长离开
现在时间:509 乘客8想做电梯,来自第4楼,去第5楼
现在时间:515 3号乘客从9楼进入电梯,想去2楼
电梯进人ing
现在楼层在9 现在时间:540
电梯准备去7楼 电梯经过8楼 ↓ 现在时间:546
现在时间:585 4号乘客等待时间过长离开
电梯准备去7楼 电梯经过7楼 ↓ 现在时间:607
实际输出: