记电梯问题的实践总结
前言:
这三次电梯问题是根据乘客的内外部请求,模拟电梯运行原理针对不同的输入来进行相应输出(包括开门、楼层变化和关门)。首先第一次电梯问题仅仅是设计好电梯运行算法就行,第二次则进行多余输入的删除,第三次则不再进行方向的输入,而是直接通过乘客请求来合并请求列表。在这三次作业中最难的是最基本的算法设计,包括输入的读取,从输入中读取有效信息形成列表,以及对请求列表 的运行等;而根据以上难点,以及第二、三次算法迭代中要实现的功能都离不开正则表达式和ArrayList的使用。本次Blog主要针对本人对电梯运行算法的改进,以及正则表达式,ArrayList的使用展开。
设计与分析:
第一次电梯问题:

类图:

算法分析:
1. 初始化阶段
-
程序启动:创建
BufferedReader读取用户输入 -
创建电梯对象:
Elevator elevator = new Elevator() -
设置楼层范围:
-
读取第一行输入作为
minFloor(最低楼层) -
读取第二行输入作为
maxFloor(最高楼层)
-
-
设置初始位置:
currentFloor = 1(电梯初始停在1楼)
2. 请求输入阶段
程序进入循环,等待用户输入请求,直到输入"END":
-
外部请求格式:
<楼层,方向> -
内部请求格式:
<楼层>
每个请求都会调用processRequest()方法处理:
-
去除
<和> -
判断是外部请求(含逗号)还是内部请求
-
检查楼层是否有效(
isValidFloor) -
将有效请求加入对应队列:
-
内部请求加入
internalRequests -
外部请求封装为
ExternalRequest对象加入externalRequests
-
3. 电梯运行阶段(elevator.run())
初始状态
-
方向初始化为UP(向上)
-
创建StringBuilder收集输出信息
-
输出初始状态:
Current Floor: 1 Direction: UP
主循环
只要hasRequests()返回true(任一队列不为空),电梯持续运行:
上行过程(moveUp)
-
当前楼层+1
-
输出当前状态
-
检查
shouldStop:-
如果当前楼层匹配内部请求队列首元素,开门关门并移除该请求
-
如果当前楼层匹配外部请求且方向相同,开门关门并移除该请求
-
如果应该改变方向(
shouldChangeDirection),则处理请求并改变方向
-
-
检查是否需要转向:
-
到达最高楼层,或
-
上方无任何请求(
!hasUpRequestsAbove() && !hasInternalRequestsAbove())
-
下行过程(moveDown)
-
当前楼层-1
-
输出当前状态
-
检查
shouldStop(逻辑同上行) -
检查是否需要转向:
-
到达最低楼层,或
-
下方无任何请求(
!hasDownRequestsBelow() && !hasInternalRequestsBelow())
-
停止条件
当两个请求队列都为空时,hasRequests()返回false,循环结束
4. 输出阶段
将StringBuilder中的运行记录输出到控制台
心得体会:

本次作业是第一次接触电梯问题,算法设计的第一大难关便是有用数据的分类读取,在此我选择用正则表达式,可以设计regx,用正则表达式来判断输入内容,用同时创建ArrayList列表,使用ArrayList中的add函数将筛选过后的信息加入不同列表,从而进行后一步的算法。其次,在本次实验中有一大问题就是当外部请求和内部请求都有相同楼层,但是外部请求的楼层是电梯向上运行时打开,内部请求的楼层是电梯向下运行时打开,而我通过与同学交流学习发现同学卡着的难点是相同的楼层只能打开一次。主要是因为我们使用了列表清楚函数,当列表中的一项被运用时及楼层等于当前楼层,列表会直接删除这1楼层。而我们的函数算法中外部楼层和内部楼层并不是同时判断的,并且内部楼层没有方向,从而导致了我们内部楼层被提前删除,进而无法实现相同楼层不同方向而开两次门的要求。在此的改进时,我们可以不用列表删除函数,而是使用链表的遍历,从而弥补算法缺陷。最后在本次作业中面临的问题是超过了内存限制的问题,在此可以将Scanner用BufferdRead因为如果用Scanner需要创建新的字符串,而BufferdRead可以在原字符串的基础上进行修改,从而减少内存的使用,提高代码效率。
第二次电梯问题:
一、


类图:

二、算法分析:
1. 初始化阶段
-
程序启动
-
创建
BufferedReader对象用于读取用户输入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); -
-
创建电梯对象
-
实例化电梯控制系统核心组件
Elevator elevator = new Elevator(minFloor, maxFloor); RequestQueue requestQueue = new RequestQueue(); ElevatorController controller = new ElevatorController(elevator, requestQueue); -
-
设置楼层范围
-
读取用户输入的前两行作为电梯运行范围
int minFloor = Integer.parseInt(br.readLine()); // 最低楼层 int maxFloor = Integer.parseInt(br.readLine()); // 最高楼层 -
-
设置初始状态
-
电梯默认停在1楼,初始方向向上
elevator.currentFloor = 1; elevator.direction = 1; // 1=UP, -1=DOWN -
2. 请求输入阶段
-
输入循环
-
持续读取输入直到遇到"END"命令
while (!(line = br.readLine().trim()).equalsIgnoreCase("END")) -
-
请求格式处理
-
外部请求格式:
<楼层,方向>如<3,UP> -
内部请求格式:
<楼层>如<5> -
去重检查避免处理相同连续请求
if (!line.equals(previousRequest)) -
-
请求处理流程
-
去除
<和>符号 -
根据是否包含逗号判断请求类型
-
验证楼层有效性
floor >= elevator.minFloor && floor <= elevator.maxFloor -
加入对应队列:
-
内部请求 →
internalRequests -
外部请求 →
externalRequests
-
-
3. 电梯运行阶段
初始状态输出
Current Floor: 1 Direction: UP
主循环控制
while (requestQueue.hasRequests()) {
if (elevator.direction == 1) {
moveUp();
} else {
moveDown();
}
}
上行过程(moveUp)
-
楼层移动
elevator.moveUp(); // currentFloor++输出新状态:
Current Floor: [X] Direction: UP -
停靠判断
-
检查是否匹配内部请求队列首元素
if (floor == requestQueue.peekInternalRequest().floor) -
检查是否匹配外部请求(方向需一致)
if (floor == requestQueue.peekExternalRequest().floor && dir == request.direction)
-
-
请求处理
-
移除已处理的请求
requestQueue.pollInternalRequest(); requestQueue.pollExternalRequest(); -
输出开关门动作
Open Door # Floor [X] Close Door
-
-
方向检查
-
到达顶层或上方无请求时转向
if (currentFloor == maxFloor || (!hasUpRequestsAbove() && !hasInternalRequestsAbove()))
-
下行过程(moveDown)
(逻辑与上行对称)
-
楼层移动:
currentFloor-- -
停靠判断:同上升逻辑
-
方向检查:到达底层或下方无请求时转向
4. 终止条件
-
当两个请求队列均为空时结束循环
public boolean hasRequests() { return !internalRequests.isEmpty() || !externalRequests.isEmpty(); }




浙公网安备 33010602011771号