电梯

一.前言
1.第一次题目集相对于后两次来说,题量大了一些,但内容简单。除(电梯程序)外,如(身份证号校验位,解一元二次方程)都只运用了简单的类的构建,锻炼了java中输出的方式,格式;还有另外两个题目(正则表达式-qq号,验证码),引入了正则表达式的使用,合理运用可以大幅度减少代码的篇幅,对于后续代码题的输入格式进行了训练,我找了一个网址[]https://codejiaonang.com/?by=history&from=kkframenew#/course/regex_chapter1/2/3(),这个网站包含了全部的正则表达式的练习。对于电梯,是本次以及这几次题目的压轴题,在第一次电梯题目集中,因为是第一次接触大规模作业,未免做起来会很吃力,与常规的电梯运行不同,其中的算法是隐含的,所以想正确的做出这道题,必须要摸清其中的算法套路。

2.第二次题目集共有三道题目,除了(电梯程序外)外,另外两个题目的难度,相对于第一次题目集的题目来说,(难了一点点,我更改了一次代码就通过了全部的测试用例),如(点与线,汽车挡风玻璃雨刷)都实行了多个类的设计,点与线中,设计了“Point”和“Line”,汽车挡风玻璃雨刷中,“Lever”,“Dial”,“Brush”,“Agent”四个类,其中每个类都遵循SRP(单一职责原则),不仅练习了提高代码的可维护性,还增强了代码可读性。最后一道压轴的电梯程序,在第一次题目原有的算法基础上,对电梯类进行了多个划分,如电梯类、乘客请求类、队列类以及控制类,使得每部分的功能更加明确,确保了代码更容易更改的同时,使代码的结构更加简明。

3.第三次题目集中,有三道题,前两个题目不是很难,只需掌握一些算法,最后一道题也是为压轴的电梯。第一题为销售步枪问题,只需要设置一个简单的销售订单类(没有很难的算法,只是简单的计算题),满足类设计的单一职责;第二道题,是一个利用蒙特卡洛方法求圆周率的问题,这道题本质上是不难的,如果要想正确的做出,需要掌握蒙特卡罗方法,可参考[]https://www.cnblogs.com/strongmore/p/14595232.html();第三道题的电梯程序,相对于前两次的外部请求为源楼层和方向,改为了源楼层和目标楼层,其中算法规则有了稍微的改变,好比在处理一个外部请求时,将目标楼层放到内部请求列队最后一个位置进行处理。

但无论如何,这三道电梯的解题关键都在于,电梯内外两个方向同时处理,优先处理同方向的请求

二.设计与分析
第一次电梯题目集的设计与分析
相信很多人和我一样,在看到第一次题目集时,复杂的题目和奇怪的输入格式,都无从下手,那就让我们从题干要求开始一步一步突破。
题目内容
设计一个电梯类,包含状态管理、请求队列管理以及调度算法。

可以观察一下测试用例(后两道题目也如此),具体的算法内容包括了,电梯何时转向,也就是电梯下一个处理的目标应该是谁,带着这样的思路,做这个题就简单很多了。
下面这个是我设计的类图:

open and close:判断电梯是否应该开门
printfloor:打印电梯状态
moveway:获取电梯下一个要到达的楼层
removefloor:移除电梯请求列表
下面是我这个程序的复杂度分析图:

根据分析结果,可以发现:
1.零注释问题(Percent Lines with Comments: 0.0%) 可能导致:代码可读性差,团队协作困难。
2.过高复杂度方法(Elevator.run() 复杂度28)
3.深度嵌套问题(Max Block Depth=6,Avg=3.24)在处理电梯内外部请求时,用了多个if/else语句,使代码显得很冗杂,且在后期管理时很难更改。
后续的改进
1.改进了run方法中的链表操作,使其复杂度从28降到了9
2.架构优化方面,Elevator类承担了过多的职责,可以将其拆分为不同的类,比如将状态管理、移动策略、请求处理等分离,使用接口和实现类来提高代码的可扩展性和可维护性。(也就是后来两次题目集的代码)

第二次电梯题目集的设计与分析
题还是原来的题,话不多说,有图有真相

根据我的类图可以发现:
此次共有六个大类
Main类:初始化输入和启动流程。主要内容还是根据正则表达式,来正确的处理输入信息,调用controller来完成运行过程。
Elevator类:维护电梯的物理状态。主要功能:验证楼层是否在允许范围内。
Controller类:核心调度逻辑。内部核心内容有三部分(1.请求处理2.移动控制3.请求清理)
RequestQuene类:管理请求。
枚举类:定义状态和方向常量。
ExternalRequest类:获取外部电梯请求。
接下来看复杂度分析图:

根据此图可得知
1.相比于第一次代码,平均复杂度降低了不少,不过这次最大复杂度居然达到了40,可能是我多加了一层嵌套结构的关系
2.值得一提的是,这次注释达到了4.1,这也使得了我的代码更有可读性,使得后期代码在更改时可能会更加容易定位
3.违背了单一职责原则,用了大量的getter和setter,而且controller中重要的方法只占了二成
后续的改进
将getnextfloor进行了拆分,因为能力有上限,最后拆完的最高复杂度还是有26,并且对此部分的代码多加了一些注释,可以方便我后续的修改

第三次电梯题目集的设计与分析
这次的题目就比较令人头疼了,与前两次的外部请求(楼层,方向),这次变为了(请求楼层和目标楼层),在原有的算法基础上加了一些改变。还是老样子,上图

在第二题的基础上去掉了外部请求类,将其换为了passenger类,其功能与之相似,都是获取外部的请求

因为这个题我并未完整的做出来,所以复杂度等相对较低,但是这个题与第二题是没有太大区别的,主要是在处理外部请求时,将其目标楼层放到内部请求列队最后一个。

三.踩坑心得
1.当第一个题目集发布出来的时候,第一天我就完成了前四道题目,然后电梯题目对我来说就是望尘莫及的了,首先,在题目难度上是一个问题就算了,对于这道题在输入中就看得我一头雾水,后来的几天,我通过找资料,找到了关于正则表达式的练习(在前言中提到的),这个问题解决后,就开始考虑做题的方法,因为是电梯运行,生活中也经常接触,所以脑子就被带进了死胡同里(这也导致了后来在运行代码时测试可以通过,但是提交答案就是运行超时的问题),这个也是令我百思不得其解啊。再后来在老师发的Look算法中找到了帮助,找到了此次电梯运行过程的正解--将乘客请求分为电梯内和电梯外两个梯队,初始电梯在一楼,分别检测内外两个列队在最前面的请求,最重点的部分来了(在运行时,要把同向的请求都处理完事时,在进行处理下一个外部请求和内部请求)--这也是解这三道题的核心思路。

2.第二个题目集没什么好说的,就是将第一题电梯中的代码分个类,不过要特别注意的是,每个类要满足“单一职责原则”。

3.第三次题目集,看似把方向请求拿走了,实际上还是需要自己去判断,因为我没注意到这一点,导致我的代码运行结果总是短短的,所以这一点要值得注意;还有另一点要值得注意的是,在处理外部请求时,不能先处理他的目标楼层,要把它放到内部请求列表屁股位,因为当时没仔细读题,我看了好久的测试用例,和自己原来的代码,都没想到运行过程为什么不一样。

四.改进建议
对于这三次题目集来说,我认为最大的缺点就是运用了大量的if/else。
1.以LOOK算法为核心逻辑
在请求上,源代码混合储存,可能无法快速获得定位,LOOK中TreeSet分上下两个队列;在方向决策上,动态监测边界;并且还能实时监测途径楼层请求。
2.完全单一职责
合理利用可以 增强代码的可维护性,比如说,在修改调度算法时,需要修改整个控制类,改进后只需要修改一个类,并且还能降低我控制类的复杂度,使得占用内存更少,运行时间会更快,
3.增添合理的注释
我的代码的可读性很低,并且一些条件判断语句显得更加冗杂,所以在每个关键的算法后增加一些注释,便于理解和修改。

五.总结
1.学到的知识
最最最首先了解到的就是我们的正则表达了,帮助我减少了大部分需要处理数据的代码,尤其是在我发的那个链接中的练习十分全面;还有更重要的部分,单一职责原则,我以后的代码之路也会严格遵守;我不光收获了知识,编程能力也大大提升,还有我的抗压力。
然而在java中,我还是有非常多不明确的语法规则,我还要多浏览此方面知识
2.建议
首先,我认为我们的每个老师(无论是任课老师,还是出题老师),对我们都是非常负责的,我觉得在课堂上,应该多给同学写代码实践的时间,比如重构代码等。


posted on 2025-04-20 14:12  哈喽看不出来  阅读(103)  评论(0)    收藏  举报

导航