题目集 5~7 的总结性 Blog
前言:
在经历了三次电梯题目集的摧残之后,有了自己的一点心得的体会,特地编写本次 Blog 来纪念我的电梯题目成长之路,去抚慰那三周的熬夜苦思冥想。现在回头去看,只感觉轻舟已过万重山。我对于三次题目集的态度,愚以为最重要在第一次的电梯题目思路的构建,这对于三次题目的迭代起到了举重若轻的作用。
第一次的电梯:起初遇见电梯题目时,第一次看见了如此庞大的已知条件,在研究过后果断放弃了(可能是对于这么长的题目有心理上的恐惧,以至于感觉很难)。但是都来看见同学们在截至时间到来的时候,都还没有做出来。我就又有想法了,开始熬了个大夜去想这个题目的逻辑到底是什么?但是可惜的是想了几种方法还没有做出,就是思路没有办法落实在代码逻辑中,总是存在漏洞!!!但是在经过老师的讲解引导之后,我又多了一种方法,但是由于和我的方法并不搭边,所以我并没有采用。继续琢磨我的方法,但是可惜的是在截至日期到来之前还是没有完善好我的思路,没有改变结果陷入死循环的最终答案。
第二次的电梯:在第二次电梯题目开始的时候,我看了一眼题目发现和第一次只是在格式上有了变化,但是地层逻辑并未改变。所以我继续我第一次题目的书写,完善思路改进方法。同时我也在不断地向老师和同学们请教思路,这导致我体会到来接近五种的不同方法(在设计与分析会具体介绍)。但是我又是在快结束时才基本完善了我的思路,但是我发现思路清晰了与成功运行之间还有好大好大的差距,我在编译代码的时候总会有无数个意想不到的地方报错。这就导致我的题目二截至之前没有得到所有的分数。
第三次的电梯:在最后一次电梯题目迎来的时候,不知不觉时间已近三周,我感觉在这三周里面自己不知不觉的就开始对敲代码感兴趣,形成了一种好像是自然而然的事情,每天想着代码的逻辑,写作业前面的第一件事就是敲几行代码。导致我到了最后一次终于可以完整的运行代码,编译代码。时至今日,发现第八周就竟然没有 pta 新的题目可做,就可惊讶不习惯。但也感谢自己终于完成了!!!
设计与分析:
1. 我的思路:
电梯问题详解:(锁定目标楼层法)
根据目前所在楼层以及目标楼层进行判断
内部请求以及外部请求
内部请求所在楼层与运行方向相同,外部请求所在楼层与运行方向相同,外部请求方向与
电梯运行同向——通过比较内部请求与外部请求距离所在楼层的距离,距离近的为目标楼
层
内部请求所在楼层与运行方向相同,外部请求所在楼层与运行方向相同,外部请求方向与
电梯运行反向——前往内部请求的楼层(即目标楼层为内部请求所在楼层)
内部请求所在楼层与运行方向相同,外部请求所在楼层与运行方向相反,外部请求方向与
电梯运行同向——前往内部请求的楼层(即目标楼层为内部请求所在楼层)
内部请求所在楼层与运行方向相同,外部请求所在楼层与运行方向相反,外部请求方向与
电梯运行反向——前往内部请求的楼层(即目标楼层为内部请求所在楼层)
内部请求所在楼层与运行方向相反,外部请求所在楼层与运行方向相同,外部请求方向与
电梯运行同向——前往外部请求的楼层(即目标楼层为外部请求所在楼层)
内部请求所在楼层与运行方向相反,外部请求所在楼层与运行方向相同,外部请求方向与
电梯运行反向——通过比较内部请求与外部请求距离所在楼层的距离,距离近的为目标楼
层
内部请求所在楼层与运行方向相反,外部请求所在楼层与运行方向相反,外部请求方向与
电梯运行同向——通过比较内部请求与外部请求距离所在楼层的距离,距离近的为目标楼
层
内部请求所在楼层与运行方向相反,外部请求所在楼层与运行方向相反,外部请求方向与
电梯运行反向——前往内部请求的楼层(即目标楼层为内部请求所在楼层)
2. 其余方法简述:
a.使用数组(楼层优先),在数组里头定义逻辑有两种不同的,记作上 行请求和下行
请求,再根据输入进行判断,逐一输出
b.是判断上下两列(方向优先),根据具体的要求方向,然后用队列,在队列里判断方向
的方法有两种,大体上还是判断队列两个对首的元素跟方向的关系,
c.是根据队列首元素判断目标楼层和方向,在今西逐一输出与判断
d.首先对输入数据进行处理,规定上行为正,下行为负,使用数字关系,进行判断。
3.剖析代码及底层逻辑:
<1>主要设计思路:
是通过模拟电梯的运行过程,处理内部请求(乘客在电梯内按下的楼层按钮)和外部请求(乘客在电梯外按下的上下行按钮)。
<2>类的设计:
ExternalRequest 类:
用于表示外部请求,包含两个属性:floor 表示请求的楼层,direction 表示请求的方向
(“UP” 或 “DOWN”)。
Elevator 类
表示电梯,负责处理内部请求和外部请求,调度电梯运行。
主要属性:
IRQueue:存储内部请求的楼层,使用 LinkedList
ERQueue:存储外部请求,使用 LinkedList
currentFloor:电梯当前所在的楼层。
Direction:电梯当前的运行方向。
主要方法:
isVectorDirection(int floor):判断目标楼层与当前楼层的方向是否一致。
getNextfloor():根据内部请求和外部请求的情况,确定电梯的下一个目标楼层。
moveToFloor(int floor):目前为空,可用于实现电梯移动到指定楼层的具体逻辑。
processRequests():处理所有请求,模拟电梯的运行过程。
Main4 类:
包含 main 方法,是程序的入口点。
读取用户输入的最小楼层和最大楼层,初始化电梯的当前楼层和运行方向。
循环读取用户输入的请求,根据请求的格式将其添加到相应的队列中。
调用 processRequests 方法处理所有请求。
<3>设计的类图:
踩坑心得:
1. 边界检查和异常处理问题(我认为最达到困难,现在看来好容易,但是在做题的时候总是注意不到,导致错误):
问题描述:代码中缺少对用户输入的边界检查和异常处理。例如,当用户输入的楼层超出了电梯可运行的最小和最大楼层范围时,程序没有进行相应的处理,可能会导致电梯运行到非法楼层。另外,当用户输入的格式不符合要求时,程序异常。
数据体现:在测试过程中,如果故意输入超出范围的楼层或错误的格式,程序会出现异常终止的情况,影响了程序的稳定性。
类设计结构影响:由于没有在合适的位置添加边界检查和异常处理逻辑。这些问题没有在类的设计中得到充分考虑,使得类的功能不够完善。
测试结果影响:测试时发现,当输入非法数据时,程序无法正常处理,这表明程序的容错力较差。
心得:在编写代码时,要充分考虑各种可能的输入情况,添加边界检查和异常处理逻辑,提高程序的健壮性和容错能力。可以在 Main4 类的输入处理部分添加对输入数据的验证,确保输入的楼层在合法范围内!
2.方法实现不完整问题(在开始研究的时候准备上设计一下这个方法,但是后来又感觉没有用):
问题描述:moveToFloor 方法为空,没有实现具体的逻辑。这可能会导致在后续的开发和测试过程中,无法准确模拟电梯的移动过程。
数据体现:由于该方法没有实现,无法对其进行测试,也就无法验证电梯移动的逻辑是否正确。
类设计结构影响:Elevator 类中定义了 moveToFloor 方法,但没有实现,破坏了类的完整性。这使得 Elevator 类的功能不够完善,无法真正实现电梯的移动功能。
测试结果影响:在测试过程中,无法验证电梯移动的正确性,因为 moveToFloor 方法没有实际功能。
心得:在设计类和方法时,要确保每个方法都有明确的功能和实现。如果暂时无法实现某个方法,可以先添加占位符,但要在后续的开发中及时完善。
3. 对于我的方法中划分的 8 小类总是容易混淆:
问题分析:在 getNextfloor 方法中,根据内部请求(IRQueue)和外部请求(ERQueue)的方向以及请求方向与电梯当前方向的一致性,划分了 8 种不同的情况进行处理。由于嵌套的 if-else 语句较多,逻辑复杂。
解决方案:代码拆分:将复杂的逻辑拆分成多个小的方法,每个方法负责处理一种或几种情况,提高代码的可读性和可维护性。
添加注释:在关键的代码段添加详细的注释,解释每种情况的处理逻辑。
4. 由于每次处理完数据没有进行删除而导致输出错误(陷入循环):
问题分析:在 processRequests 方法中,虽然调用了 getNextfloor 方法获取目标楼层,但在某些情况下,可能没有正确地从请求队列中移除已经处理过的请求,导致请求队列中的数据一直存在,从而陷入无限循环。
解决方案:确保在 getNextfloor 方法中,每次返回目标楼层时,都从相应的请求队列中移除该请求。
5. 边界的细节问题:
队列空的边界问题:在 getNextfloor 方法中,虽然对队列是否为空进行了部分检查,但在某些复杂的嵌套条件下,可能会出现队列空指针异常的风险。
方向合法性边界问题:代码中假设输入的方向只有 "UP" 和 "DOWN",但没有对输入的方向进行合法性检查,可能会导致程序在处理非法方向输入时出错。
6. . 代码逻辑复杂性问题:
问题描述:getNextfloor 方法中存在大量嵌套的 if-else 语句,逻辑复杂,代码可读性差。类设计结构影响:这种复杂的逻辑集中在 Elevator 类的一个方法中,破坏了类的单一职责原则。Elevator 类不仅要管理电梯的状态和请求队列,还要处理复杂的调度逻辑,导致类的职责不清晰。
测试结果影响:复杂的逻辑增加了测试的难度,需要设计大量的测试用例来覆盖所有可能的情况。在测试过程中,可能会发现一些隐藏的逻辑错误。
心得:在编写代码时,应尽量避免过度嵌套和复杂的逻辑。可以将复杂的逻辑拆分成多个小的方法,每个方法只负责一个明确的功能,提高代码的可读性和可维护性。
改进与建议:
1.代码可读性方面
注释优化:虽然已有部分注释,但可进一步细化,尤其是在复杂逻辑处,如 getNextfloor方法中众多嵌套的 if-else 语句,要详细解释每个判断分支的目的和处理逻辑,方便后续维护者理解。
2. 变量和方法命名:
部分命名不够清晰,需要规范。
3.代码结构和可维护性方面
逻辑拆分:getNextfloor 方法逻辑过于复杂,嵌套层级深,应将不同的判断逻辑拆分成多个独立的小方法,提高代码的可维护性和可测试性。
4.模块化设计:
可以将输入处理、电梯调度、电梯移动等功能进一步模块化,每个模块负责单一功能,降低代码耦合度,便于后续扩展新功能。
5.错误处理:
输入验证:在接收用户输入时,缺乏对输入合法性的检查,如输入的楼层是否在 min 和max 范围内,方向是否为合法的 “UP” 或 “DOWN”,应添加相应的验证逻辑。
6.性能方面
队列操作优化:在 getNextfloor 方法中频繁使用 peek() 和 pop() 方法,可考虑使用更高效的数据结构或算法来优化调度逻辑,提高性能。
总结:
学习收获
- Java 的基础学习:
类与对象的运用:通过定义 ExternalRequest 类和 Elevator 类,理解了如何创建自定义类,以及如何使用构造函数来初始化对象的属性。例如,ExternalRequest 类用于外部请求的楼层和方向信息,Elevator 类则负责管理电梯的运行逻辑。 - 算法设计
逻辑设计:在设计电梯调度算法时,需要考虑多种情况,如内部请求和外部请求的优先级
方向一致性等。 - 逻辑思维能力的提升
3.多角度思考问题
需要进一步学习和研究的地方: - 代码优化
可读性优化:当前代码中 getNextfloor 方法的逻辑较为复杂,嵌套的 if-else 语句过多,导致代码的可读性较差。需要学习如何通过提取方法、添加注释等方式来提高代码的可读性和可维护性。
性能优化:在处理大量请求时,LinkedList 的性能可能会受到影响。 - 异常处理
输入验证:代码中缺乏对用户输入的合法性检查,如输入的楼层是否在合法范围内、方向是否为有效值等。需要学习如何添加输入验证逻辑,避免因用户输入错误而导致程序崩溃。 - 设计模式
可扩展性:当前代码的结构相对固定,若要添加新的功能, - 测试与调试
我目前对于调试还存在问题,在代码报错时往往求助于 AI,个人的纠错能力还不足,需要进行测试与调试的训练