关于PTA电梯多次迭代的总结与反思
1、前言
在PTA第5到7次题目集中,我们对于控制电梯以及对其进行相关功能进行迭代进行编码实现。整体而言,这几次题目集对于我们基本编码能力的要求较高,同时对于各方面的能力都有一定要求,如关于look算法的运用,正则表达式,类的单一职责运用等。其次,题量较大,第一次基本需要花费很长时间完成,后续对第一次代码进行复用,减少了对时间的消耗。最后,电梯的设计存在一定难度,在设计和迭代的时候是一个很烧脑的过程,但在成功通过的时候,是一个非常令人激动以及高兴的。现在的我再回顾本次迭代的过程,确实从中收获了很多。
2、设计与分析
第一次电梯设计分析
题目:
设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。
电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:
运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
在第一次电梯设计过程中,一开始估计大家也都确实是被这样的难题给吓到了,以至于在一开始的几天里没有人能做出来。随后的几天里,大家不断在PTA上分享各自的逻辑以及测试案例,随后陆续有人通过了本次测试。而我在周六开始对该题目的设计。当时是根据题目的要求对电梯设计了一个电梯类和主类,然后按照老师在QQ群的提示开始尝试使用正则表达式进行编写,通过寻找是否存在UP或DOWN来给对于电梯的请求进行排分类。如果存在,则将本次输入放入out数组中,否则in数组。随后要对于两个数组的信息进行处理,此时也是和之前一样的思路处理含字符的输入内容,用正则将整数提取出来。当时其实对于如何具体操作电梯基本没有什么思路的。直到下一个周一,尝试用while循环把各种可能囊括在循环里,即分别设计两个整型变量,记录in和out的长度,再设计一个整型数组,对于此前的的UP和DOWN进行区分,up为1,down为0,长度等于out的长度。这个时候思路就基本已经出来了,然后对while内部进行设计,最后成功通过测试。

通过图片也可以看出,我这次的分支语句占比大,占到了26.2%。以及没有注释,最大复杂度为39,说明了本次代码各种意义上而言都不算是好的代码,很大程度上都需要进行改进。

类与类之间的关系少,联系性强。
第二次电梯设计分析
输入输出要求和第一题差不多,新加了类的设计(包含但不限于乘客请求类、电梯类、请求队列类及控制类,其中控制类专门负责电梯调度过程)。以及要处理如下情况:
乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
在本次设计中,主要要求关于单一职责来设计多个类,将原本的两个类的各种内容分配到各个类中。对于类的设计比原来要求更高,于是先尝试根据题目的类要求大概分配类的作用。确定了控制类为控制电梯上下楼,电梯类为电梯的基本属性,请求类为处理电梯的内外具体需求,排队控制类为处理输入的数据。初次之外,还发现了有部分情况第一次设计没考虑完备的情况

第二次可以看到,分支语句和复杂度相比第一次都有一定程度的下降。

多类设计
第三次电梯设计分析
电梯运行规则与前阶段相同,但有如下变动情况:
乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
此次电梯设计主要将原本的外部请求UP和DOWN改成了数字,通过数字来确定升降。此次设计是将排队控制类改成乘客类并和原来一样处理输入数据,用了replace方法,将外部请求分为两份,第一份为和原本外部请求一样,另一份放入内部请求。然后,再对请求类进行修改:当内部请求数小于等于原本内部请求时照常运行,反之则查看是否有新数据,有就用新数据继续与外部对比,无则运行外部请求。

第三次分支语句含量进一步降低,复杂度和第二次差不多。

3、踩坑心得
第一次
一开始没注意到题目输入格式中的end不区分大小写,导致只设置了小写的情况,导致出错。
没有考虑到当内外数组第一个值相等时的问题。
第二次
第一次残留下来的问题,未深入考虑内部请求与电梯方向相反时,外部请求楼层的大小问题。如:电梯上升且现在楼层大于内部请求楼层时,应该进一步考虑外部请求楼层是否大于现在楼层,如果是则上升至外部楼层,否则电梯状态改为下降。而一开始我写的是直接改为下降,所以关于这类的思考当时没有很详细。
类之间的数据传输存在问题。
输入格式未完善好,存在输入一定值会格式错乱的问题
第三次
当只剩下外部数组时,运行完外部数组加入内部后会发生无法输出内部数组的情况。
4、改进建议
本次电梯的设计总体而言还是存在挺多问题的,主要为以下几个方面
注释方面:代码里的注释较少,尤其是复杂逻辑部分缺乏注释,这会让后续维护和理解变得困难,在以后的编码中,应该尽量增加注释,像这次对代码总结时,我自己也需要花费一定的时间才能自己的代码的意思。
规范性方面:look方法中的逻辑较为复杂,存在较多嵌套的if-else语句,后续如果要改进,应该考虑使用更简洁的算法或数据结构来优化逻辑,提升代码的执行效率。还有就是类的单一职责不过明确。
错误处理方面:有很多对于输入的错误方面没有进行处理,健壮性比较低
效率方面:部分代码逻辑存在重复,如第三次实验中ex方法在Passenger和Request类中都有定义,可尽量将其提炼出来,只用一次ex方法解决问题。
解耦方面:降低耦合度,提高可修改性
5、总结
学到的东西
编程基础:通过编写这段代码,对 Java 语言的基本语法、类和对象的概念有了更深入的理解。学会了如何定义类、创建对象以及在类中定义成员变量和方法。
逻辑设计:实现电梯控制系统的过程中,锻炼了逻辑思维能力,学会了如何分析问题并将其转化为程序逻辑。学会了在遇到输出中含不同类型时使用look算法。
正则表达式运用:了解了正则表达式在Java中的使用,通过Pattern和Matcher类实现对字符串的模式匹配,用于解析乘客请求的格式。
代码修改:学会了如何在原来的基础上对代码进行修改。
需要进一步学习的点
在复杂的情况下,对于类的单一职责设计仍然存在一定问题,需要进一步的联系。
可读性差,需要进一步做好自己写代码的规范。
虽然代码实现了基本功能,但在性能和效率方面还有提升空间。需要研究更多的代码优化技巧,如减少不必要的计算、合理使用缓存等,以提高程序的运行效率。
对课程建议
可以每次这种较为复杂的题目都开放PTA社区供大家讨论。
组织课程内容的总结回顾活动,帮助学生梳理知识点,巩固所学内容。
可以多给一些测试点,尽量能达到能过测试点就基本程序通过这种情况。

浙公网安备 33010602011771号