PTA_OOP_题目集5-7电梯调度问题总结心得
一、前言
知识点
这三次题目集围绕电梯调度问题展开,涵盖了丰富的面向对象编程知识点。在类的设计与封装方面,设计了多个核心类,如Elevator类、RequestQueue类、ExternalRequest类以及Controllor类等。Elevator类封装了电梯的运行状态,包括当前楼层、运行方向、最小和最大楼层等属性,同时提供了相关的操作方法,如改变方向、设置楼层等,充分体现了面向对象的封装特性,将电梯的属性和行为进行了有效整合 。RequestQueue类则负责管理请求队列,通过内部和外部请求队列,实现对乘客请求的存储和处理,这涉及到数据结构的运用,选择LinkedList来存储请求,利用其在插入和删除操作上的高效性,优化请求处理的效率。
枚举类型的使用也是一个重要知识点,通过定义Direction枚举(UP、DOWN、IDLE)来清晰表示电梯的运行方向,使得代码的可读性和可维护性大大提高,避免了使用魔法值带来的潜在错误。在业务逻辑实现上,涉及到复杂的电梯调度算法,如根据请求判断电梯的运行方向、确定停靠楼层以及处理请求的先后顺序等,这些逻辑的实现需要对问题进行深入分析和抽象,将现实中的电梯运行场景转化为计算机可执行的代码逻辑。
题量与难度
题目集5 - 7中,关于电梯调度的题目数量逐渐增多。题目集5主要侧重于搭建基本的电梯调度框架,定义关键类和初步实现简单的调度逻辑,题量相对较少,但为后续的深入学习奠定了基础。题目集6在题目集5的基础上,对电梯调度的业务逻辑进行了细化,如增加了外部请求格式的变化以及将外部请求目的楼层加入内部请求队列的要求,题量有所增加,难度也相应提升,需要开发者对代码进行更细致的修改和完善。题目集7进一步拓展了电梯调度的功能,可能涉及到多电梯调度、更复杂的请求优先级处理等内容,题量进一步增多,难度显著加大,要求开发者具备较强的问题分析和解决能力,以及对面向对象编程的深入理解和熟练运用。
从难度梯度来看,三次题目集呈现出循序渐进的特点。题目集5是入门级别,帮助开发者熟悉电梯调度问题的基本概念和面向对象编程的初步应用;题目集6是进阶阶段,通过对业务逻辑的深化,提升开发者对代码的优化和扩展能力;题目集7则是挑战级别,考验开发者在复杂场景下综合运用知识的能力,以及对系统性能和稳定性的把控。
二、设计与分析
题目集5 - 7单部电梯调度问题源码分析
以最终提交的题目集6代码为例,
使用SourceMonitor对代码进行分析。代码有较好的可读性,在开发过程中注重对关键逻辑的解释和说明。通过对代码的分析,发现各个类的职责明确,结构清晰。
Source Monitor分析结果:
从PowerDesigner生成的类图,
可以更直观地看到各个类之间的关系。Elevator类是整个电梯调度系统的核心,它与RequestQueue类紧密协作。RequestQueue类包含内部请求队列和外部请求队列,负责管理乘客的请求。ExternalRequest类用于表示外部请求,包含源楼层和目的楼层两个关键信息。Controllor类则是整个系统的控制中枢,它协调Elevator类和RequestQueue类,实现电梯的调度逻辑。
在Elevator类中, move 方法是实现电梯移动的关键。该方法根据当前的运行方向(通过 getDirection 方法获取)来更新当前楼层(使用 setCurrentFloor 方法),并输出当前楼层和方向信息。例如:
public void move() {
if (getDirection() == Direction.UP) {
setCurrentFloor(getCurrentFloor() + 1);
System.out.println("Current Floor: " + getCurrentFloor() + " Direction: " + getDirection());
} else if (getDirection() == Direction.DOWN) {
setCurrentFloor(getCurrentFloor() - 1);
System.out.println("Current Floor: " + getCurrentFloor() + " Direction: " + getDirection());
}
}
Source Monitor分析结果:
这段代码简洁明了,通过条件判断实现了电梯的向上和向下移动,并且将电梯的运行状态及时输出,便于调试和监控。
RequestQueue类中的 addInternalRequest 和 addExternalRequest 方法分别用于添加内部请求和外部请求。在添加请求时,会先检查请求的楼层是否在有效范围内(通过与电梯的最小和最大楼层进行比较),然后再将请求添加到相应的队列中。这一过程体现了对数据的有效性验证,确保了请求队列中数据的合理性。
public void addInternalRequest(int floor, int minFloor, int maxFloor) {
if (floor >= minFloor && floor <= maxFloor) {
if (internalRequests.isEmpty() ||!internalRequests.getLast().equals(floor)) {
internalRequests.add(floor);
}
}
}
Controllor类中的 processRequests 方法是整个电梯调度的核心逻辑所在。该方法通过一个循环不断处理请求队列中的请求,直到所有请求都被处理完毕。在循环内部,调用 move 方法移动电梯,并在电梯到达请求楼层时,处理相应的请求,包括开门、将外部请求的目的楼层加入内部请求队列等操作。
public void processRequests() {
int iterationCount = 0;
while (!out.isEmpty() ||!in.isEmpty()) {
if (iterationCount >= MAX_ITERATIONS) {
System.out.println("达到最大循环次数,程序终止。");
break;
}
iterationCount++;
move();
}
}
Source Monitor分析结果:
通过对代码的分析可以看出,整个电梯调度系统的设计遵循了面向对象的设计原则,各个类之间相互协作,共同完成电梯调度的功能。然而,在实际开发过程中,也发现了一些可以优化的地方,例如在处理请求时,可以进一步优化算法,提高请求处理的效率,减少不必要的循环和判断操作。
三、采坑心得
运行超时问题
在提交题目集6的代码时,遇到了运行超时的问题。通过对代码的分析和调试,发现主要原因是在请求处理的循环中,没有对循环次数进行有效的控制,导致在某些极端情况下,如请求队列中存在大量无效或循环引用的请求时,程序陷入死循环。例如,在 processRequests 方法的 while 循环中,如果请求队列没有正确更新,就会导致循环无法结束。
最初错误的循环代码
while (!out.isEmpty() ||!in.isEmpty()) {
move();
}
经过分析,添加了循环次数限制,当循环次数达到一定值时,终止程序,并输出提示信息。
int iterationCount = 0;
while (!out.isEmpty() ||!in.isEmpty()) {
if (iterationCount >= MAX_ITERATIONS) {
System.out.println("达到最大循环次数,程序终止。");
break;
}
iterationCount++;
move();
}
通过这一修改,有效避免了运行超时的问题,同时也提高了代码的健壮性。
方向判断错误
在实现电梯方向判断逻辑时,遇到了方向判断错误的问题。电梯在运行过程中,没有按照预期的方向改变,导致运行路径错误。通过仔细检查代码,发现是在判断是否有向上或向下的请求时,逻辑不够严谨。例如,在 hasUpRequest 和 hasDownRequest 方法中,没有全面考虑内部请求和外部请求的情况。
最初错误的hasUpRequest方法
private boolean hasUpRequest() {
for (Integer req : in) {
if (req > elevator.getCurrentFloor()) {
return true;
}
}
return false;
}
上述代码只检查了内部请求队列中是否有向上的请求,忽略了外部请求队列。修改后的代码如下:
修改后的hasUpRequest方法
private boolean hasUpRequest() {
for (Integer req : in) {
if (req > elevator.getCurrentFloor()) {
return true;
}
}
for (ExternalRequest req : out) {
if (req.getSourceFloor() > elevator.getCurrentFloor() || req.getDestinationFloor() > elevator.getCurrentFloor()) {
return true;
}
}
return false;
}
通过全面检查内部请求和外部请求队列,确保了电梯方向判断的准确性,解决了电梯运行路径错误的问题。
输出结果与预期不符
在测试过程中,还遇到了输出结果与预期不符的问题。经过仔细对比运行结果和预期结果,发现是在处理请求顺序上存在问题。例如,在处理外部请求和内部请求时,没有按照正确的优先级顺序处理,导致电梯在某些楼层没有按照预期停靠。通过重新梳理请求处理逻辑,先处理外部请求,再处理内部请求,并且在处理请求时,确保按照楼层顺序依次处理,解决了输出结果与预期不符的问题。
四、改进建议
代码性能优化
在请求处理逻辑中,可以考虑使用更高效的数据结构和算法。例如,在判断是否有某个方向的请求时,可以使用更高效的查找算法,或者将请求队列按照楼层顺序进行排序,这样可以减少查找和判断的时间复杂度。同时,在处理请求时,可以采用多线程技术,提高请求处理的并行性,特别是在多电梯调度的场景下,多线程可以显著提升系统的性能。
代码结构优化
对于一些复杂的方法,如 processRequests 和 move 方法,可以进一步拆分,将不同的功能模块封装成独立的方法,提高代码的可读性和可维护性。例如,可以将方向判断、请求处理、电梯移动等功能分别封装成不同的方法,使得代码结构更加清晰,便于后续的修改和扩展。
五、总结
学习收获
通过参与题目集 5 - 7 中电梯调度问题的求解,我在知识掌握、编程技能以及问题处理等多方面都取得了长足进步。
深入理解面向对象编程
在解决电梯调度问题过程中,我对面向对象编程的理解达到了新高度。设计 Elevator 类时,将电梯的楼层、运行方向、状态等属性以及移动、改变方向等行为封装其中,深刻领会了封装性的精髓,它不仅保护了数据的完整性,还使得代码结构更加紧凑和安全。同时,在构建 RequestQueue 类管理请求时,清晰地划分了不同请求队列(内部和外部),明确了类的职责单一性原则,这极大提升了代码的可读性与可维护性。通过这些实践,我学会了如何根据实际问题合理抽象出类,并将相关功能准确分配到各个类中,让程序结构更加清晰合理。
数据结构与算法应用能力提升
这一系列题目让我熟练掌握了多种数据结构在实际场景中的运用。使用 LinkedList 存储请求队列,利用其在插入和删除操作上的高效特性,优化了请求处理的流程。在处理复杂的请求逻辑时,例如判断电梯运行方向,需要综合考虑内部和外部请求队列中的信息,通过设计合理的算法遍历这些数据结构,准确判断电梯应采取的行动。这不仅锻炼了我对数据结构的操作能力,更提升了我根据实际需求选择最合适数据结构和算法的能力,明白了不同数据结构和算法在不同场景下的优劣,为今后解决更复杂的编程问题积累了宝贵经验。
强大的问题解决与调试能力
开发过程中遭遇了诸多棘手问题,如运行超时、方向判断错误以及输出结果与预期不符等。面对运行超时,通过细致分析代码,发现是请求处理循环缺乏次数控制导致死循环。通过添加循环次数限制,成功解决该问题,这让我学会在代码中设置合理的边界条件,避免程序陷入异常状态。在解决方向判断错误时,仔细检查相关逻辑,发现是判断方法未全面涵盖内部和外部请求情况,修改后确保了电梯运行方向的正确判定。处理输出结果不符预期问题时,重新梳理请求处理优先级和顺序,最终使程序输出符合预期。在不断调试和解决这些问题的过程中,我掌握了多种调试技巧,如设置断点、输出关键变量值等,能够快速定位问题根源,极大地提升了我的问题解决能力和编程自信心。
编程习惯与思维的养成
这三次题目集的练习促使我养成了良好的编程习惯。在编写代码时,注重添加注释,不仅方便自己回顾代码逻辑,也有利于他人阅读和理解。同时,在代码结构设计上追求简洁明了,将复杂功能拆分成多个小的、易于管理的模块。在思维层面,学会从整体上规划程序架构,先确定各个类的职责和相互关系,再逐步实现具体功能,培养了系统性的编程思维。这种思维方式将对我今后解决各类编程问题产生深远影响,帮助我更高效、更优质地完成编程任务。
需进一步学习研究的地方
在代码性能优化方面,虽然已经采取了一些措施,但仍有提升空间。需要进一步学习和研究算法优化、数据结构选择等方面的知识,以提高代码在大规模请求下的运行效率。在设计模式方面,目前的代码虽然遵循了面向对象的设计原则,但可以进一步探索使用设计模式来优化代码结构,提高代码的可扩展性和可维护性。例如,可以考虑使用策略模式来优化电梯运行策略的实现,使用观察者模式来实现对电梯状态的监控和通知。
对课程相关方面的建议
对于老师教学,建议在讲解面向对象编程知识时,可以结合更多实际项目案例,如电梯调度、图书馆管理系统等,帮助学生更好地理解和应用知识。
通过对这三次题目集的学习和实践,在编程能力和问题解决能力方面都取得了显著的进步,同时也明确了自己在学习过程中需要进一步提升的方向。希望在后续的学习中,能够将所学知识应用到更多实际项目中,不断提高自己的编程水平。
浙公网安备 33010602011771号