单部电梯调度程序--第一次blog作业

一、前言
刚刚完成的三次题目集的练习,这些题目涵盖了数据结构、算法设计以及实际问题的模拟等多个方面,对我来说确实很难,得分情况也很不如意,第一次题目集只拿了30分,电梯一题完全没写出来,第二次得了100分,在尝试多次之后终于是完成了,第三次拿了88分,电梯第一个测试点没过。那段时间我每天都在反复检查逻辑、修改代码,电梯的方向判断总是出错,是否开门的逻辑也总是和我想的不一样,想了很多办法也没用,外部请求的处理也不够完善,代码里还充斥着大量重复的部分。过程很痛苦,但当我终于看到程序正确运行的那一刻,那种成就感是无法用言语表达的。

二、设计与分析
(1)题目:设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。

输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:

运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door



第一次还没写出来,也还没写注释,后面才发现是忽略了输入格式<>,所以一直非零返回,一直写不出来,所以不多讲,大致就是分了内外两个队列,每次通过两个队头比较决定电梯是移动到上一层还是下一层,如果当前楼层与队头请求匹配就清除队头。

(2)对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类
电梯运行规则与前阶段单类设计相同,但要处理如下情况:
乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
注意:本次作业类设计必须符合如上要求(包含但不限于乘客请求类、电梯类、请求队列类及控制类,其中控制类专门负责电梯调度过程),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次电梯程序提交到本次题目中测试)。



意识到了题目一的错误,加了正则,终于可以运行了,但是是错误的,发现有些楼层的是否开门实现错误,决定方向也有问题。最后细化了一下是否停靠的逻辑,对一些特殊情况做了处理,如图

在一些情况会跳过外部请求先执行内部请求,比如说,当方向向下时,且外部请求楼层大于内部请求楼层,就要先执行内部请求,我是像上面一样,写了一个while,移动电梯到内部队头请求楼层,然后清除了内部队头,这样就实现了特殊情况的外部请求跳过。

然后发现对于重复请求,最后的结果会很奇怪,于是在Controller加上了lastInput来储存上一个请求,要是请求相同就会跳过。

但是还是有的测试样例是错的,最后才发现是我搞错了电梯决定方向的逻辑(同向优先一开始没明白),于是又细化了决定方向的逻辑,如图
![],一开始我以为的同向优先是对下一个请求来说的,后面才发现是还要考虑当前电梯的运行方向。(https://img2024.cnblogs.com/blog/3634651/202504/3634651-20250420195133611-1798959214.png)

在这里修正了同向优先的逻辑,增加了一些情况要考虑当前运行方向逻辑,然后就一下通过了所有测试点。

(3)之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,具体设计可参考如下类图。
电梯运行规则与前阶段相同,但有如下变动情况:

乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<请求源楼层,请求目的楼层>,其中,请求源楼层表示乘客发起请求所在的楼层,请求目的楼层表示乘客想要到达的楼层。
当输入“end”时代表输入结束(end不区分大小写)。



由于这次多加了一个Passenger类,外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>,就先加了决定外部请求的请求方向,如图

然后其他的逻辑就没怎么大改,但是第一个测试点过不去。在内外部请求楼层相同的时候就会出错,因为开一次门两个请求都被处理了,于是改来改去,要么内部请求不开门,要么外部请求不开门。。。总之就是过不去。

三、踩坑心得
在这次编程练习中,我踩了不少坑,也从这些坑中学到了很多宝贵的经验。
方向判断逻辑错误:最初,我对电梯的方向判断逻辑理解不够透彻,导致电梯的移动方向总是与预期不符。这让我意识到,对于电梯这类需要精确控制的系统,逻辑判断必须非常严谨。我通过不断测试和调整,最终找到了问题所在,并重新设计了方向判断逻辑,确保电梯能够根据乘客的请求正确地决定移动方向。
是否开门逻辑错误:在处理电梯是否需要开门的逻辑时,我也遇到了难题。有时候电梯会在不应该开门的情况下开门,或者在需要开门时却关闭。这让我认识到,对于电梯这类自动化设备,每一个决策点都需要精确的逻辑判断。我通过细化是否停靠的逻辑,特别是对特殊情况进行处理,最终解决了这个问题。
处理重复请求:在处理乘客请求时,我最初没有考虑到重复请求的情况。当程序接收到连续的相同请求时,会导致电梯做出异常的反应。我通过在控制器中添加逻辑来存储和比较上一个请求,忽略重复的请求,从而解决了这个问题。
职责过多的问题:在最初的设计中,电梯类承担了过多的职责,这不仅使得代码难以维护,也增加了代码的复杂性。我通过将职责分配到不同的类中,如乘客请求类、电梯类、队列类和控制类,遵循单一职责原则,使代码更加清晰和易于维护。
在处理乘客请求时,我最初没有很好地处理无效或不合理的请求,比如请求的楼层数超出了电梯的楼层范围。我添加了逻辑来自动忽略这些无效或不合理的输入,使程序更加健壮。这让我学会了在设计系统时要考虑输入的有效性验证。

四、改进建议
增加注释:我没怎么写注释,这让我在回顾代码时感到困难。我计划增加必要的注释来解释代码逻辑,尤其是复杂的算法和逻辑判断部分,以提高代码的可读性。注释不仅有助于他人理解代码,也是自我回顾和维护的重要工具。
模块化设计:我将功能进一步分解到独立的模块或类中,比如请求处理、电梯控制和用户输入解析等,这样做可以降低系统的复杂性,提高代码的可维护性。模块化设计有助于将复杂问题分解为更小、更易于管理的部分。
代码风格和规范:遵循统一的代码风格和编程规范,如命名约定、格式化规则等,使代码更加整洁和一致。

五、总结
这三次的编程练习,我感觉自己崩溃了无数次,不过还是有了一些收获。在编程技能方面,我学到了很多。我不仅学会了如何设计和实现一个复杂的电梯调度系统,还学会了如何使用Java编程语言来处理各种数据结构和算法问题。在解决问题的能力上,我也有了显著的提高。面对复杂的问题,我学会了如何拆解问题,一步步分析,找到解决问题的关键点。这种能力不仅在编程中有用,在日常生活中遇到问题时也同样适用。这三次练习也让我的心态发生了很大的变化。从最初的焦虑和无助,到最后的平静和自信,我学会了如何在压力下保持冷静,如何从失败中吸取教训,如何坚持不懈地追求目标。尽管我取得了一些进步,但我也意识到自己在算法和数据结构方面的知识还不够扎实。这在解决一些复杂问题时显得尤为明显。我计划在这方面加强学习,提高自己的算法设计和优化能力。此外,我还需要学习更多关于代码优化的知识,比如如何写出更高效的代码,如何减少时间和空间复杂度。最后,我意识到持续学习和实践的重要性。编程是一个不断学习和进步的过程,我需要不断学习新的技术和方法,并在实践中不断改进和优化我的代码。
总的来说,这次编程练习虽然让我吃了不少苦头,但也让我成长了很多。

posted @ 2025-04-20 21:34  张仪嘉  阅读(72)  评论(0)    收藏  举报