题目集5~7电梯问题
一、前言
初涉 Java 编程,电梯问题就给我带来了巨大挑战。看似平常的电梯运行场景,实则涉及一个比较复杂的楼层调度、状态管理、请求优先级处理等难题。编码时,频繁出现的逻辑漏洞和错误,让我也意识到了自己在编程方面的不足之处。例如,我的代码结构不够清晰、代码的可读性和可维护性较差等。为了提高自己的编程水平,我将继续学习和实践,不断地改进自己的编程习惯和方法。
总的来说,电梯问题是我 Java 编程学习中的一个重要里程碑。通过解决这个问题,我不仅掌握了 Java 编程的基本技能,也提高了自己的问题解决能力和编程水平。在未来的学习和工作中,我将继续努力,不断地提高自己的编程能力,为实现自己的职业目标打下坚实的基础。
二、设计与分析
第一次电梯
题目如下
【设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。】
我的分析:初步知道了题目要求然后进行电梯的运动基本规律,电梯初始停在 1 层,状态停止、方向无。有请求即启动,优先选同向且近的请求定方向,若无同向请求则依反向请求确定。运行中每到一层,判断有无同向匹配请求,有则停梯开门处理并移除请求,无则继续移动。当前方向请求处理完就转向,直到内外请求队列为空,电梯停止运行,方向变回无,停在最后楼层。
对第一次的代码SourceMontor的生成报表如下

高复杂度方法集中在请求处理与方向判断逻辑,反映出单一方法承担多重职责(如队列操作、状态更新、楼层校验),违背单一职责原则,导致维护困难。
第二次电梯
给出了更多要求和具体类图
【1、乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
2、乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>】

根据这些要求开始对源代码进行修改,用这个类图对我的代码进行再一次的设计多出了RequestQueue类,Controller类,多了个枚举State。关于这个新功能我把他设计在了Controller类processRequest()里。
控制类Controller的加入分离输入处理与电梯调度逻辑。
对第二次的代码SourceMontor的生成报表如下

很显然1,2方法并没有被简化多少,不过平均复杂度和深度还是减低了。
第三次电梯
【对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,具体设计可参考如下类图。】【电梯运行规则与前阶段相同,但有如下变动情况:
乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)】

因为输入发生了变化,所以使用类Passenger类,对之前的代码进行再一次书写,完善。
分析:电梯类(Elevator):负责状态(当前楼层、运行方向、运行状态)管理和运行逻辑(移动、开门 / 关门、请求处理);
乘客类(Passenger):封装请求数据,包含楼层合法性校验(避免无效楼层输入);
队列类(RequestQueue):管理内外请求队列,支持去重和按规则入队(如外部请求处理后将目的楼层加入内部队列尾部);
控制类(Controller):协调用户输入、请求分发和电梯调度,处理输入解析与格式转换(如将用户输入的 “源 - 目的” 格式转换为Passenger对象)。
对第三次的代码SourceMontor的生成报表如下

这次因为代码的内容更加全面修改之前代码的漏洞,所以深度和复杂度都有所提高。
三、踩坑心得
1、对电梯方向的判断
电梯方向在最开始的时候,我以为是现实生活中的那种方向判断,然后想了半天没有想到。然后通过老师的提醒,知道了要按方向进行区分,然后因为又想偷懒,考虑方向时,优先级也只有向上,然后电梯档案也没有全部正确,部分正确。最后改正过来向上时优先级是向上,如果有向上的就先向上;向下时,优先级是向下,如果有向下的,就先向下,题目七的电梯全部答案才正确。
总结:
初始错误:误将 “当前移动方向” 与 “请求方向” 直接绑定,未考虑 “顺路请求”(如电梯上行时,高层的下行请求不在当前方向路径上,应忽略)。
解决方案:定义 “有效请求” 条件:
上行时,仅处理目标楼层≥当前楼层的内部请求,或当前楼层的上行外部请求;
下行时,仅处理目标楼层≤当前楼层的内部请求,或当前楼层的下行外部请求。
关键结论:方向判断需结合电梯当前运动方向与请求的 “路径相关性”,而非简单匹配请求方向。
2、对链表的处理
如果对链表数组进行遍历去删除重复的元素的话,要注意链表的下标。因为你删除之后,如果下标不变的话,有可能会跳过某一个链表,可能会导致数组越界,我在题目集二的时候就没考虑到这个问题,导致一直非零返回。
总结:
问题场景:遍历队列删除重复请求时,直接使用下标递增(如for (int i=0; i<list.size(); i++)),删除元素后list.size()变化,导致下标越界或漏删。
解决方法:

3、对数据的处理
最先开始是想把数据一个一个读取,这样的处理方式很慢,而且不能集中处理运行电梯,然后通过老师的数据处理的启发,知道了,可以一次性把数据全部读取到String里,在对这个String进行处理提取数据,并把这些数据集中储存在两个链表中,方便后续对电梯运行的处理。
总结:
初始方案:逐行读取输入并立即处理,导致电梯频繁启停,逻辑混乱(如处理一个请求后需重新计算方向)。
改进方案:一次性读取所有输入,解析为Passenger列表,批量加入请求队列,统一由电梯调度算法按规则处理。
核心优势:符合题目 “串行处理请求” 要求,避免实时输入与电梯运行的异步冲突,简化调度逻辑。
四、改进建议
1、代码可读性与可维护性
类注释:说明设计职责(如Elevator类的状态转移逻辑,RequestQueue的去重规则)。
方法注释:参数含义、返回值说明、核心逻辑步骤(如determineDirection()方法的方向判断算法)。
关键变量:标注状态变量的合法取值范围(如currentFloor的取值为[minFloor, maxFloor])。
提取公共方法:将重复逻辑(如楼层合法性校验、请求去重)封装为工具方法,避免代码冗余。
2、算法复杂度优化
目前的调度算法在处理大规模请求时可能会出现性能瓶颈。可以考虑使用更高效的算法来优化电梯的调度逻辑。比如,使用优先队列(堆)来管理请求队列,根据请求的优先级(如距离当前电梯位置的远近)对请求进行排序,这样在选择下一个停靠楼层时可以更快速地找到最优解。
3、操作界面优化
如果后续添加图形化界面,可以进一步优化界面设计,使其更加美观和易用。例如,使用不同的颜色和图标来表示电梯的不同状态(如绿色表示运行,红色表示故障),使用动画效果来模拟电梯的移动和开门关门过程,提升用户体验。
4、异常处理与提示
当用户输入无效请求或程序出现异常情况时,要给用户提供明确的提示信息。例如,当用户输入的楼层超出范围时,提示 “输入的楼层超出有效范围,请重新输入”,让用户清楚知道问题所在并进行修正。
五、总结
1、技术收获
面向对象设计:通过三次迭代,深刻理解单一职责、开闭原则,学会将复杂问题拆解为高内聚、低耦合的类结构。
调度算法:掌握 “同向优先” 策略的实现细节,理解路径规划中 “顺路处理” 的逻辑建模。
问题解决流程:遵循 “需求分析→原型设计→迭代优化→测试验证” 的开发循环,通过代码度量工具(SourceMonitor)定位复杂度瓶颈,针对性优化。
2、不足与改进
目前实现未考虑并发请求(题目简化为串行处理),未来可探索多线程环境下的电梯调度(如使用队列锁保证线程安全);此外,可添加图形化界面(Swing/AWT)模拟电梯运行过程,增强交互性。
3、职业能力提升
电梯问题的解决过程不仅是技术的实践,更是工程思维的锻炼:从初始的代码混乱到最终的结构清晰,我学会了通过模块化设计降低复杂度,通过测试用例验证逻辑正确性,这些经验将直接应用于未来的软件开发中。
此次实践让我认识到,编程能力的提升始于对细节的雕琢 —— 无论是状态转移的边界条件,还是集合操作的下标处理,唯有严谨对待每一个逻辑分支,才能构建出健壮、可维护的系统。未来我将继续深耕算法与设计模式,挑战更复杂的工程问题,逐步向专业开发者迈进。

浙公网安备 33010602011771号