Blog作业1
一.个人感受
经过了这三次的迭代作业,我认识到了完成一个大项目就要先把它拆分成几个小部分,有这几个小部分组合在一起才能完成一个大工程的运行,这几个小部分之间藕断丝连交错混杂丰富多彩的关系可以上演一部甄嬛传。就是这三次电梯的作业让小小劳资感受到了强大的编程力量,直接给我一个暴击让我认识自己和高手之间的差距。其实,还是很开心做这次迭代作业的,虽然改了又错,错了又改还是没有做出来但是这次体验还是很棒的。至少,它让我明白了自己的不足,让我知道了和其他人的差距,对之后的学习改进也提供了帮助。其实,我在做第一次电梯题目的时候,听到他们讲很难很难,在还没开始做之前就开始畏惧了,心理上就已经害怕了。心里侥幸觉得既然很难,那应该也没什么人会做出来,所以就也没这么认真去对待这是一方面,另一方面是自己本身基础就不是很好再加上对电梯运行的逻辑没有搞懂所以给作业难度再加上一层buff。第一次没做出来,然后后面也有接续做只能说进步了离成功还差一点。其实,在做这三次作业的过程中也挺焦虑的,焦虑自己做不出来,焦虑其他同学一个接一个的答案正确,焦虑自己技不如人。我想希望这份焦虑能促进我前进的动力吧
二.三次电梯迭代作业分析
1.题目集05单部电梯调度程序
- 第一次电梯题目查看
点击查看题目
设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。
电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:
运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
输入样例:
在这里给出一组输入。例如:
1
20
<3,UP>
<5>
<6,DOWN>
<7>
<3>
end
输出样例:
在这里给出相应的输出。例如:
Current Floor: 1 Direction: UP
Current Floor: 2 Direction: UP
Current Floor: 3 Direction: UP
Open Door # Floor 3
Close Door
Current Floor: 4 Direction: UP
Current Floor: 5 Direction: UP
Open Door # Floor 5
Close Door
Current Floor: 6 Direction: UP
Current Floor: 7 Direction: UP
Open Door # Floor 7
Close Door
Current Floor: 6 Direction: DOWN
Open Door # Floor 6
Close Door
Current Floor: 5 Direction: DOWN
Current Floor: 4 Direction: DOWN
Current Floor: 3 Direction: DOWN
Open Door # Floor 3
Close Door
-
题目分析
首先题目要求设计一个电梯类里面包含最大楼层,最小楼层,当前楼层,运行方向,运行状态以及内外请求队列,其中外请求队列里不仅要包含楼层还要包含方向。楼层默认在1楼,一次性从键盘输入所有数据分别生成内部请求和外部请求。键盘输入的时候要判断输入是否有效,是否大于最小楼层小于最大楼层,要注意处理无效请求情况。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。如果两个请求都不为空,根据两个请求判断电梯运行的方向,电梯开始移动,当电梯向某个方向移动的时候,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。同时还要处理已经执行过的请求移>点击查看代码
![]()
-
我的代码
点击查看代码
import java.util.*;
// 定义电梯运行方向枚举
enum Direction {
UP, DOWN, IDLE
}
// 定义电梯类
class Elevator {
private int minFloor;
private int maxFloor;
private int currentFloor;
private Direction direction;
private Queue<Integer> internalRequests;
private Map<Integer, Map<Direction, Boolean>> externalRequests;
// 构造函数
public Elevator(int minFloor, int maxFloor) {
this.minFloor = minFloor;
this.maxFloor = maxFloor;
this.currentFloor = minFloor;
this.direction = Direction.IDLE;
this.internalRequests = new LinkedList<>();
this.externalRequests = new HashMap<>();
}
// 添加内部请求
public void addInternalRequest(int floor) {
if (isValidFloor(floor)) {
if (!internalRequests.contains(floor)) {
internalRequests.add(floor);
}
} else {
System.out.println("Invalid floor request: " + floor);
}
}
// 添加外部请求
public void addExternalRequest(int floor, Direction direction) {
if (isValidFloor(floor)) {
externalRequests.putIfAbsent(floor, new HashMap<>());
externalRequests.get(floor).put(direction, true);
} else {
System.out.println("Invalid floor request: " + floor);
}
}
// 获取内部请求队列
public Queue<Integer> getInternalRequests() {
return internalRequests;
}
// 获取外部请求队列
public Map<Integer, Map<Direction, Boolean>> getExternalRequests() {
return externalRequests;
}
// 处理请求
public void processRequests() {
if (internalRequests.isEmpty() && externalRequests.isEmpty()) {
return;
}
if (direction == Direction.IDLE) {
if (!internalRequests.isEmpty()) {
direction = internalRequests.peek() > currentFloor? Direction.UP : Direction.DOWN;
} else if (!externalRequests.isEmpty()) {
int firstFloor = externalRequests.keySet().iterator().next();
direction = externalRequests.get(firstFloor).containsKey(Direction.UP)? Direction.UP : Direction.DOWN;
}
}
while (!internalRequests.isEmpty() || !externalRequests.isEmpty()) {
if (direction == Direction.UP) {
int nextFloor = findNextRequestFloorAbove();
if (nextFloor == -1) {
direction = Direction.DOWN;
continue;
}
while (currentFloor < nextFloor) {
currentFloor++;
System.out.println("Current Floor: " + currentFloor + " Direction: UP");
}
openAndCloseDoor();
} else if (direction == Direction.DOWN) {
int nextFloor = findNextRequestFloorBelow();
if (nextFloor == -1) {
direction = Direction.UP;
continue;
}
while (currentFloor > nextFloor) {
currentFloor--;
System.out.println("Current Floor: " + currentFloor + " Direction: DOWN");
}
openAndCloseDoor();
}
}
}
// 查找上方的下一个请求楼层
private int findNextRequestFloorAbove() {
int nextFloor = Integer.MAX_VALUE;
for (int floor : internalRequests) {
if (floor > currentFloor && floor < nextFloor) {
nextFloor = floor;
}
}
for (int floor : externalRequests.keySet()) {
if (floor > currentFloor && floor < nextFloor) {
nextFloor = floor;
}
}
return nextFloor == Integer.MAX_VALUE? -1 : nextFloor;
}
// 查找下方的下一个请求楼层
private int findNextRequestFloorBelow() {
int nextFloor = Integer.MIN_VALUE;
for (int floor : internalRequests) {
if (floor < currentFloor && floor > nextFloor) {
nextFloor = floor;
}
}
for (int floor : externalRequests.keySet()) {
if (floor < currentFloor && floor > nextFloor) {
nextFloor = floor;
}
}
return nextFloor == Integer.MIN_VALUE? -1 : nextFloor;
}
// 开门和关门
private void openAndCloseDoor() {
System.out.println("Open Door # Floor " + currentFloor);
if (internalRequests.contains(currentFloor)) {
internalRequests.remove(currentFloor);
}
if (externalRequests.containsKey(currentFloor)) {
externalRequests.remove(currentFloor);
}
System.out.println("Close Door");
}
// 检查楼层是否有效
private boolean isValidFloor(int floor) {
return floor >= minFloor && floor <= maxFloor;
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String data; // 输入数据:字符串
int floor = 0;
Direction direction = null;
int minFloor, maxFloor; // 电梯最低楼层、最高楼层
String request = ""; // 提取出的乘客请求字符串
List<String> list = new ArrayList<>(); // 用于接收用户输入的数组
// 读取最小楼层
if (input.hasNextInt()) {
minFloor = input.nextInt();
} else {
System.out.println("Invalid input for min floor.");
input.close();
return;
}
// 读取最大楼层
if (input.hasNextInt()) {
maxFloor = input.nextInt();
} else {
System.out.println("Invalid input for max floor.");
input.close();
return;
}
Elevator elevator = new Elevator(minFloor, maxFloor);
input.nextLine(); // 消耗掉换行符
while (input.hasNextLine()) {
data = input.nextLine();
if (data.equalsIgnoreCase("end")) {
break;
}
list.add(data);
}
for (String req : list) {
request = req;
if (request.contains(",")) { // 外部请求
if (!request.matches("<\\d+,\\s*(UP|DOWN)>")) {
System.out.println("Wrong Format");
} else {
String[] parts = request.replaceAll("[<>]", "").split(",");
if (parts.length == 2 && parts[0].trim().matches("\\d+")) {
floor = Integer.parseInt(parts[0].trim());
direction = Direction.valueOf(parts[1].trim().toUpperCase());
elevator.addExternalRequest(floor, direction); // 外部请求入队,格式为<楼层数,方向>
} else {
System.out.println("Wrong Format");
}
}
} else {
if (!request.matches("<\\d+>")) { // 内部请求
System.out.println("Wrong Format");
} else {
floor = Integer.parseInt(request.replaceAll("[<>]", ""));
elevator.addInternalRequest(floor); // 内部请求入队,格式为<楼层数>
}
}
}
while (!elevator.getInternalRequests().isEmpty() || !elevator.getExternalRequests().isEmpty()) {
elevator.processRequests(); // 一次性处理所有的内、外部乘客请求
}
input.close();
}
}
1.类和结构:
代码定义了 Elevator 类来模拟电梯的行为,包含了电梯的各种属性(如最小楼层、最大楼层、当前楼层、运行方向等)以及处理请求的方法。
还有一个 Main 类用于从控制台读取用户输入并驱动电梯的运行。
定义了 Direction 枚举来表示电梯的运行方向(上、下、空闲)。
2.方法功能:
Elevator 类的构造函数初始化了电梯的基本属性。
addInternalRequest 和 addExternalRequest 方法分别用于添加电梯内部和外部的请求,并对请求楼层的有效性进行检查。
processRequests 方法是核心逻辑,根据电梯当前的方向和请求队列,决定电梯的移动和请求处理。
findNextRequestFloorAbove 和 findNextRequestFloorBelow 方法用于查找电梯上方和下方的下一个请求楼层。
openAndCloseDoor 方法处理电梯到达楼层时的开门和关门操作,并移除已处理的请求。
3.输入处理:
在 Main 类中,通过 Scanner 从控制台读取用户输入的最小楼层、最大楼层以及一系列请求。
对输入的请求进行格式检查,区分内部请求(格式为 <楼层数>)和外部请求(格式为 <楼层数,方向>),并将合法请求添加到电梯的相应请求队列中。
- 代码分析
![]()
点击查看代码分析
Metrics Details For File '0512.txt'
--------------------------------------------------------------------------------------------
Parameter Value
========= =====
Project Directory D:\SM\
Project Name Baseline
Checkpoint Name Baseline
File Name 0512.txt
Lines 221
Statements 125
Percent Branch Statements 32.0
Method Call Statements 63
Percent Lines with Comments 10.0
Classes and Interfaces 2
Methods per Class 3.50
Average Statements per Method 15.71
Line Number of Most Complex Method 146
Name of Most Complex Method Main.main()
Maximum Complexity 2
Line Number of Deepest Block 75
Maximum Block Depth 4
Average Block Depth 1.49
Average Complexity 2.00
--------------------------------------------------------------------------------------------
Most Complex Methods in 1 Class(es): Complexity, Statements, Max Depth, Calls
Main.main() 2, 10, 2, 3
--------------------------------------------------------------------------------------------
Block Depth Statements
0 36
1 31
2 29
3 19
4 10
5 0
6 0
7 0
8 0
9+ 0
--------------------------------------------------------------------------------------------
分析主要从代码规模、代码结构与复杂度、方法相关等维度展开,同时结合代码中的具体实现逻辑来解释各项指标的意义和影响。
| 分析维度 | 具体指标 | 指标值 | 结合代码的分析说明 |
|---|---|---|---|
| 代码规模 | 行数 | 221 行 | 整体代码行数处于适中水平,代码文件不算冗长,包含了 Elevator 类和 Main 类的完整逻辑实现,涵盖了电梯的属性定义、请求处理方法以及用户输入处理等功能 |
| 语句数 | 125 条 | 平均每行约 0.57 条语句(125 / 221 ≈ 0.57),代码密度较为均匀,说明代码没有出现过于紧凑或松散的情况,语句分布相对合理 | |
| 类和接口数量 | 2 个(Elevator 类和 Main 类) |
代码结构相对简单,仅包含两个类。Elevator 类负责电梯相关的属性管理和操作逻辑,Main 类用于处理用户输入和控制电梯的运行流程,没有过多复杂的层次关系,便于理解和维护 |
|
| 每个类的方法数 | 平均 3.50 个/类 | 每个类的方法数量较少,表明类的职责相对单一。Elevator 类包含构造函数以及添加请求、处理请求、开关门等方法;Main 类主要是 main 方法来处理输入逻辑,没有出现一个类包含大量方法导致职责混乱的情况 |
|
| 平均每个方法的语句数 | 15.71 条 | 部分方法可能包含较多的逻辑,如 Elevator 类的 processRequests 方法和 Main 类的 main 方法等。虽然平均语句数不算极高,但仍需关注这些方法的可读性和维护性,确保逻辑清晰,必要时可进一步拆分复杂方法 |
|
| 代码结构和复杂度 | 分支语句百分比 | 32.0% | 约三分之一的语句为分支语句(如 if、else 等)。在代码中,Elevator 类的 processRequests 方法中通过大量的 if-else 判断来确定电梯的运行方向和处理请求逻辑,以及 Main 类中对用户输入的格式检查和请求类型判断等都使用了分支语句,这增加了代码的逻辑复杂度,需要仔细测试以确保各种分支情况都能正确处理 |
| 方法调用语句数 | 63 条 | 方法之间调用频繁,体现了一定的模块化设计。例如,processRequests 方法调用了 findNextRequestFloorAbove 和 findNextRequestFloorBelow 方法来查找上下方的请求楼层,还调用了 openAndCloseDoor 方法来处理开关门操作,这种模块化的设计使得代码结构更清晰,便于维护和扩展 |
|
| 注释行百分比 | 10.0% | 有一定比例的注释,对理解代码有帮助,但可以考虑进一步增加注释,尤其是对于复杂的逻辑部分。如 Elevator 类中一些方法的实现逻辑相对复杂,增加注释可以更好地说明代码的意图和功能,提高代码的可读性 |
|
最复杂方法信息(Main.main()) |
行号 | 146 行 | main 方法是最复杂的方法,位于 146 行。它负责处理用户输入的读取、格式检查、请求解析以及驱动电梯处理请求的整个流程,涉及多个逻辑步骤和条件判断,因此复杂度相对较高 |
| 最大复杂度 | 2 | 复杂度相对较低,说明 main 方法虽然是最复杂的,但整体逻辑不是特别复杂。可能是由于方法中主要的逻辑是顺序执行的输入处理和调用电梯的方法,没有过于复杂的嵌套或递归逻辑 |
|
| 最深块深度 | 2 | 方法中嵌套层次最深为 2 层,结构不算特别复杂。在 main 方法中,主要的嵌套逻辑体现在对用户输入的解析和请求处理的循环中,没有出现深度嵌套导致逻辑难以理解的情况 |
|
| 方法调用数 | 3 次 | main 方法调用了 3 个其他方法,包括创建 Elevator 对象的构造函数以及调用 Elevator 类的 addInternalRequest、addExternalRequest 和 processRequests 等方法来实现电梯的功能,体现了方法之间的调用关系和代码的组织方式 |
|
| 整体代码复杂度 | 最大复杂度 | 2 | 整体代码的复杂度处于较低水平,相对容易理解和维护。尽管有一定比例的分支语句和方法调用,但代码结构较为清晰,类和方法的职责明确,没有出现过于复杂的算法或数据结构 |
| 最深块深度 | 4 | 代码中存在嵌套层次达 4 层的情况(可能在 Elevator 类某些方法中),如 processRequests 方法中在确定电梯运行方向和查找请求楼层的逻辑中可能存在多层嵌套。这可能会使部分代码逻辑较难理解,需要关注这些深层嵌套的部分是否可以优化,以提高代码的可读性和性能 |
|
| 平均块深度 | 1.49 | 平均嵌套深度较浅,整体代码结构在块嵌套方面不算特别复杂。说明大部分代码的逻辑结构较为扁平,只有少部分代码存在较深的嵌套,整体代码的可读性和维护性相对较好 | |
| 块深度与语句分布 | 块深度 0 的语句数 | 36 条 | 大部分逻辑嵌套层次在 1 层及以下,但仍有一定数量语句处于较深嵌套层次,尤其是块深度为 2、3、4 的语句有一定比例。块深度为 0 的语句可能是一些简单的变量声明、初始化或直接的方法调用等基础操作,如 Main 类中初始化 Scanner 对象和定义变量等语句 |
| 块深度 1 的语句数 | 31 条 | 块深度为 1 的语句可能包含一些简单的条件判断或循环,如 Main 类中对用户输入的读取循环和基本的格式检查等 |
|
| 块深度 2 的语句数 | 29 条 | 块深度为 2 的语句可能涉及更复杂一些的逻辑,如 Elevator 类中在处理请求时的一些条件判断和逻辑分支,嵌套在其他逻辑内部 |
|
| 块深度 3 的语句数 | 19 条 | 块深度为 3 的语句进一步增加了逻辑的复杂性,可能是在处理请求过程中更深入的条件判断或对请求队列的复杂操作 | |
| 块深度 4 的语句数 | 10 条 | 块深度为 4 的语句是代码中嵌套最深的部分,可能是在 Elevator 类的核心请求处理逻辑中,对请求的查找、方向判断以及开关门操作的综合处理中出现的深层嵌套,这些部分需要特别关注优化以降低复杂度 |
|
| 块深度 5 及以上的语句数 | 0 条 | 代码中没有出现块深度达到 5 及以上的情况,说明代码的嵌套深度在可接受范围内,没有出现极端复杂的嵌套逻辑 |
- 改进后代码以及分析
点击查看代码
import java.util.*;
// 定义电梯运行方向枚举
enum Direction {
UP, DOWN, IDLE
}
// 定义电梯类
class Elevator {
private int minFloor;
private int maxFloor;
private int currentFloor;
private Direction direction;
private Queue<Integer> internalRequests;
private Map<Integer, Map<Direction, Boolean>> externalRequests;
// 构造函数
public Elevator(int minFloor, int maxFloor) {
this.minFloor = minFloor;
this.maxFloor = maxFloor;
this.currentFloor = minFloor;
this.direction = Direction.IDLE;
this.internalRequests = new LinkedList<>();
this.externalRequests = new HashMap<>();
}
// 添加内部请求
public void addInternalRequest(int floor) {
if (isValidFloor(floor)) {
if (!internalRequests.contains(floor)) {
internalRequests.add(floor);
}
} else {
System.out.println("Invalid floor request: " + floor);
}
}
// 添加外部请求
public void addExternalRequest(int floor, Direction direction) {
if (isValidFloor(floor)) {
externalRequests.putIfAbsent(floor, new HashMap<>());
externalRequests.get(floor).put(direction, true);
} else {
System.out.println("Invalid floor request: " + floor);
}
}
// 获取内部请求队列
public Queue<Integer> getInternalRequests() {
return internalRequests;
}
// 获取外部请求队列
public Map<Integer, Map<Direction, Boolean>> getExternalRequests() {
return externalRequests;
}
// 处理请求
public void processRequests() {
if (internalRequests.isEmpty() && externalRequests.isEmpty()) {
return;
}
if (direction == Direction.IDLE) {
if (!internalRequests.isEmpty()) {
direction = internalRequests.peek() > currentFloor? Direction.UP : Direction.DOWN;
} else if (!externalRequests.isEmpty()) {
int firstFloor = externalRequests.keySet().iterator().next();
direction = externalRequests.get(firstFloor).containsKey(Direction.UP)? Direction.UP : Direction.DOWN;
}
}
while (true) {
if (direction == Direction.UP) {
currentFloor++;
if (hasRequestAtCurrentFloor()) {
System.out.println("Current Floor: " + currentFloor + " Direction: UP");
openAndCloseDoor();
} else if (hasRequestsAbove()) {
System.out.println("Current Floor: " + currentFloor + " Direction: UP");
} else {
direction = Direction.DOWN;
}
} else if (direction == Direction.DOWN) {
currentFloor--;
if (hasRequestAtCurrentFloor()) {
System.out.println("Current Floor: " + currentFloor + " Direction: DOWN");
openAndCloseDoor();
} else if (hasRequestsBelow()) {
System.out.println("Current Floor: " + currentFloor + " Direction: DOWN");
} else {
direction = Direction.UP;
}
}
if (internalRequests.isEmpty() && externalRequests.isEmpty()) {
break;
}
}
}
// 检查当前楼层是否有请求
private boolean hasRequestAtCurrentFloor() {
return internalRequests.contains(currentFloor) || externalRequests.containsKey(currentFloor);
}
// 检查上方是否有请求
private boolean hasRequestsAbove() {
for (int floor : internalRequests) {
if (floor > currentFloor) {
return true;
}
}
for (int floor : externalRequests.keySet()) {
if (floor > currentFloor) {
return true;
}
}
return false;
}
// 检查下方是否有请求
private boolean hasRequestsBelow() {
for (int floor : internalRequests) {
if (floor < currentFloor) {
return true;
}
}
for (int floor : externalRequests.keySet()) {
if (floor < currentFloor) {
return true;
}
}
return false;
}
// 开门和关门
private void openAndCloseDoor() {
System.out.println("Open Door # Floor " + currentFloor);
if (internalRequests.contains(currentFloor)) {
internalRequests.remove(currentFloor);
}
if (externalRequests.containsKey(currentFloor)) {
externalRequests.remove(currentFloor);
}
System.out.println("Close Door");
}
// 检查楼层是否有效
private boolean isValidFloor(int floor) {
return floor >= minFloor && floor <= maxFloor;
}
}
public class Main {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
String data; // 输入数据:字符串
int floor = 0;
Direction direction = null;
int minFloor, maxFloor; // 电梯最低楼层、最高楼层
String request = ""; // 提取出的乘客请求字符串
List<String> list = new ArrayList<>(); // 用于接收用户输入的数组
// 读取最小楼层
if (input.hasNextInt()) {
minFloor = input.nextInt();
} else {
System.out.println("Invalid input for min floor.");
input.close();
return;
}
// 读取最大楼层
if (input.hasNextInt()) {
maxFloor = input.nextInt();
} else {
System.out.println("Invalid input for max floor.");
input.close();
return;
}
Elevator elevator = new Elevator(minFloor, maxFloor);
input.nextLine(); // 消耗掉换行符
while (input.hasNextLine()) {
data = input.nextLine();
if (data.equalsIgnoreCase("end")) {
break;
}
list.add(data);
}
for (String req : list) {
request = req;
if (request.contains(",")) { // 外部请求
if (!request.matches("<\\d+,\\s*(UP|DOWN)>")) {
System.out.println("Wrong Format");
} else {
String[] parts = request.replaceAll("[<>]", "").split(",");
if (parts.length == 2 && parts[0].trim().matches("\\d+")) {
floor = Integer.parseInt(parts[0].trim());
direction = Direction.valueOf(parts[1].trim().toUpperCase());
elevator.addExternalRequest(floor, direction); // 外部请求入队,格式为<楼层数,方向>
} else {
System.out.println("Wrong Format");
}
}
} else {
if (!request.matches("<\\d+>")) { // 内部请求
System.out.println("Wrong Format");
} else {
floor = Integer.parseInt(request.replaceAll("[<>]", ""));
elevator.addInternalRequest(floor); // 内部请求入队,格式为<楼层数>
}
}
}
while (!elevator.getInternalRequests().isEmpty() || !elevator.getExternalRequests().isEmpty()) {
elevator.processRequests(); // 一次性处理所有的内、外部乘客请求
}
input.close();
}
}

点击查看代码分析
Metrics Details For File '0513.txt'
--------------------------------------------------------------------------------------------
Parameter Value
========= =====
Project Directory D:\SM\
Project Name Baseline
Checkpoint Name Baseline
File Name 0513.txt
Lines 226
Statements 130
Percent Branch Statements 33.1
Method Call Statements 69
Percent Lines with Comments 10.2
Classes and Interfaces 2
Methods per Class 5.00
Average Statements per Method 11.50
Line Number of Most Complex Method 153
Name of Most Complex Method Main.main()
Maximum Complexity 2
Line Number of Deepest Block 75
Maximum Block Depth 4
Average Block Depth 1.62
Average Complexity 2.00
--------------------------------------------------------------------------------------------
Most Complex Methods in 1 Class(es): Complexity, Statements, Max Depth, Calls
Main.main() 2, 10, 2, 3
--------------------------------------------------------------------------------------------
Block Depth Statements
0 31
1 34
2 30
3 23
4 12
5 0
6 0
7 0
8 0
9+ 0
--------------------------------------------------------------------------------------------
| 分析维度 | 具体指标 | 指标值 | 结合代码的分析说明 |
|---|---|---|---|
| 代码规模 | 行数 | 226 行 | 代码行数相对适中,不算冗长。涵盖了 Elevator 类和 Main 类的完整实现,包括电梯属性管理、请求处理逻辑以及用户输入处理等功能模块,整体结构较为紧凑。 |
| 语句数 | 130 条 | 平均每行约有 0.58 条语句(130 / 226 ≈ 0.58),语句密度较为均匀,说明代码没有出现过于紧凑或松散的情况,代码布局较为合理。 | |
| 类和接口数量 | 2 个(Elevator 类和 Main 类) |
代码结构相对简单,仅包含两个类。Elevator 类负责实现电梯的核心功能,如请求处理、状态管理等;Main 类用于处理用户输入和控制电梯的运行流程,层次关系清晰,便于理解和维护。 |
|
| 每个类的方法数 | 平均 5.00 个/类 | 每个类的方法数量适中,表明类的职责划分相对明确。Elevator 类包含构造函数以及多个处理请求、检查楼层等方法;Main 类主要是 main 方法来处理输入和控制流程,没有出现类的职责过于集中或分散的情况。 |
|
| 平均每个方法的语句数 | 11.50 条 | 平均每个方法的语句数处于合理范围,部分方法可能包含较多逻辑,但整体上方法的规模较为可控。例如 Elevator 类的 processRequests 方法和 Main 类的 main 方法,虽然包含一定逻辑,但不至于过于复杂,仍具有较好的可读性和维护性。 |
|
| 代码结构和复杂度 | 分支语句百分比 | 33.1% | 约三分之一的语句为分支语句(如 if、else 等)。在代码中,Elevator 类的 processRequests 方法中大量使用 if-else 来判断电梯运行方向、检查当前楼层请求等;Main 类中对用户输入的格式判断也使用了分支语句,这增加了代码的逻辑复杂度,需要全面测试以确保各种分支情况的正确性。 |
| 方法调用语句数 | 69 条 | 方法之间调用较为频繁,体现了良好的模块化设计。例如 processRequests 方法调用了 hasRequestAtCurrentFloor、hasRequestsAbove、hasRequestsBelow 和 openAndCloseDoor 等方法,这种模块化的方式使代码结构清晰,便于代码的复用和扩展。 |
|
| 注释行百分比 | 10.2% | 有一定比例的注释,对理解代码有一定帮助,但仍可进一步增加注释,特别是对于复杂的逻辑部分。例如 Elevator 类中一些核心方法的实现逻辑,增加注释可以更好地解释代码意图,提高代码的可维护性。 |
|
最复杂方法信息(Main.main()) |
行号 | 153 行 | main 方法是最复杂的方法,位于 153 行。该方法承担了从用户获取输入、解析输入、创建电梯对象以及驱动电梯处理请求的整个流程,涉及多个步骤和逻辑判断,因此复杂度相对较高。 |
| 最大复杂度 | 2 | 复杂度相对较低,说明 main 方法虽然是最复杂的,但整体逻辑并非极其复杂。主要是顺序执行输入处理和调用电梯相关方法,没有复杂的递归或深度嵌套逻辑,相对容易理解和调试。 |
|
| 最深块深度 | 2 | 方法中嵌套层次最深为 2 层,结构不算特别复杂。main 方法中主要的嵌套体现在对用户输入的循环处理以及根据输入类型进行的条件判断中,没有出现深度嵌套导致逻辑难以理解的情况。 |
|
| 方法调用数 | 3 次 | main 方法调用了 3 个其他方法,包括创建 Elevator 对象的构造函数以及调用 Elevator 类的 addInternalRequest、addExternalRequest 和 processRequests 等方法,通过这些方法调用来实现电梯系统的功能,展示了方法之间的调用关系和代码的组织架构。 |
|
| 整体代码复杂度 | 最大复杂度 | 2 | 整体代码的复杂度处于较低水平,相对容易理解和维护。尽管存在一定比例的分支语句和方法调用,但代码的逻辑结构较为清晰,类和方法的功能明确,没有复杂的算法或数据结构,适合进一步的开发和维护。 |
| 最深块深度 | 4 | 代码中存在嵌套层次达 4 层的情况(可能在 Elevator 类某些方法中),例如 Elevator 类的 processRequests 方法中在判断电梯运行方向和检查请求时可能存在多层嵌套逻辑。这部分深层嵌套的代码可能会增加理解和维护的难度,需要关注是否可以进行优化以提高代码的可读性和性能。 |
|
| 平均块深度 | 1.62 | 平均嵌套深度较浅,整体代码结构在块嵌套方面不算特别复杂。说明大部分代码的逻辑结构较为扁平,只有少部分代码存在较深的嵌套,整体代码的可读性和可维护性相对较好。 | |
| 块深度与语句分布 | 块深度 0 的语句数 | 31 条 | 大部分逻辑嵌套层次在 1 层及以下,但仍有一定数量语句处于较深嵌套层次。块深度为 0 的语句可能是一些基本的变量声明、初始化操作或简单的方法调用,如 Main 类中初始化 Scanner 和定义变量的语句。 |
| 块深度 1 的语句数 | 34 条 | 块深度为 1 的语句可能包含一些简单的条件判断或循环,例如 Main 类中对用户输入的读取循环以及 Elevator 类中一些简单的条件判断逻辑。 |
|
| 块深度 2 的语句数 | 30 条 | 块深度为 2 的语句可能涉及更复杂一些的逻辑,比如 Elevator 类中在处理请求时对请求队列的操作和条件判断,嵌套在其他逻辑内部。 |
|
| 块深度 3 的语句数 | 23 条 | 块深度为 3 的语句进一步增加了逻辑的复杂性,可能是在 Elevator 类中对电梯运行方向的详细判断以及对不同类型请求的综合处理逻辑。 |
|
| 块深度 4 的语句数 | 12 条 | 块深度为 4 的语句是代码中嵌套最深的部分,可能出现在 Elevator 类的核心请求处理逻辑中,如对请求的精确检查和电梯状态的调整等操作,这部分代码需要特别关注优化以降低复杂度。 |
|
| 块深度 5 及以上的语句数 | 0 条 | 代码中没有出现块深度达到 5 及以上的情况,说明代码的嵌套深度在可接受范围内,没有出现极端复杂的嵌套结构,保证了代码的相对简洁和可维护性。 |
点击查看前后代码对比分析
1.processRequests 方法的逻辑流程不同:
第一段代码:
在确定方向后,通过调用 findNextRequestFloorAbove 或 findNextRequestFloorBelow 方法找到下一个要到达的请求楼层,然后电梯会一次性移动到该楼层,再进行开门和关门操作。例如,如果当前方向是向上(Direction.UP),会调用 findNextRequestFloorAbove 找到上方最近的请求楼层,然后通过循环将电梯移动到该楼层。
第二段代码:
电梯每次移动一层,然后检查当前楼层是否有请求。如果有请求,则开门和关门处理请求;如果当前楼层没有请求但上方(或下方,根据当前方向)还有请求,则继续保持当前方向移动;如果当前楼层没有请求且上方(或下方)也没有请求,则改变方向。例如,当方向为向上(Direction.UP)时,电梯先上升一层,然后判断 hasRequestAtCurrentFloor 和 hasRequestsAbove 来决定后续操作。
2.辅助方法不同:
第一段代码:
有 findNextRequestFloorAbove 和 findNextRequestFloorBelow 方法,用于分别查找上方和下方的下一个请求楼层。这些方法通过遍历内部请求队列和外部请求队列,找到距离当前楼层最近的请求楼层。
有 hasRequestAtCurrentFloor、hasRequestsAbove 和 hasRequestsBelow 方法,用于判断当前楼层是否有请求、上方是否有请求和下方是否有请求。这些方法主要是通过检查内部请求队列和外部请求队列中是否包含当前楼层或相应方向的楼层来进行判断。
3.移动的粒度和判断时机不同:
第一段代码是先找到目标楼层再移动,移动过程中不会在中间楼层停留(除非目标楼层就是中间楼层),只有到达目标楼层后才会检查并处理请求。
第二段代码是每次移动一层,每移动一层就检查当前楼层的请求情况,并根据上下方是否还有请求来决定是否继续保持当前方向移动或改变方向。
第二段代码:
| 对比指标 | 0513.txt | 0512.txt | 差异分析 |
|---|---|---|---|
| 代码规模 | |||
| 行数 | 226 行 | 221 行 | 0513.txt 比 0512.txt 多 5 行,总体代码量都适中 |
| 语句数 | 130 条 | 125 条 | 0513.txt 语句数稍多,平均每行语句数相近,代码紧凑程度类似 |
| 类和接口数量 | 2 个 | 2 个 | 均由 Elevator 类和 Main 类构成,结构一致 |
| 每个类的方法数 | 平均 5.00 个 / 类 | 平均 3.50 个 / 类 | 0513.txt 类的方法数更多,职责划分可能更细 |
| 平均每个方法的语句数 | 11.50 条 | 15.71 条 | 0512.txt 方法内逻辑可能更复杂,0513.txt 方法更简洁 |
| 代码结构和复杂度 | |||
| 分支语句百分比 | 33.1% | 32.0% | 0513.txt 分支语句比例略高,逻辑判断可能更多 |
| 方法调用语句数 | 69 条 | 63 条 | 0513.txt 方法调用更多,模块化程度更强 |
| 注释行百分比 | 10.2% | 10.0% | 注释比例接近,均有提升空间以增强可读性 |
| 最复杂方法(Main.main ()) | |||
| 行号 | 153 行 | 146 行 | 0513.txt 中该方法位置更靠后 |
| 最大复杂度 | 2 | 2 | 复杂程度相当,逻辑复杂度较低 |
| 最深块深度 | 2 | 2 | 嵌套层次最深均为 2 层,结构复杂程度类似 |
| 方法调用数 | 3 次 | 3 次 | 对其他方法依赖程度一致 |
| 整体代码复杂度 | |||
| 最大复杂度 | 2 | 2 | 最复杂部分复杂程度相同,代码易理解维护 |
| 最深块深度 | 4 | 4 | 均存在嵌套 4 层情况,或在 Elevator 类核心逻辑,需关注优化 |
| 平均块深度 | 1.62 | 1.49 | 0513.txt 平均嵌套程度略深,整体结构不算复杂 |
| 块深度与语句分布 | |||
| 块深度 0 的语句数 | 31 条 | 36 条 | 0512.txt 中此深度语句多,多为基本操作语句 |
| 块深度 1 的语句数 | 34 条 | 31 条 | 0513.txt 此深度语句稍多,或在简单逻辑上更多 |
| 块深度 2 的语句数 | 30 条 | 29 条 | 两者相近,中等复杂逻辑嵌套代码量相当 |
| 块深度 3 的语句数 | 23 条 | 19 条 | 0513.txt 此深度语句更多,复杂逻辑处理更细致 |
| 块深度 4 的语句数 | 12 条 | 10 条 | 0513.txt 此深度语句更多,需关注此部分复杂逻辑优化 |
| 块深度 5 及以上的语句数 | 0 条 | 0 条 | 均无此深度语句,嵌套深度在可接受范围 |
- 挫折与心路历程
一开始在自己做这个电梯题目的时候,内部请求队列和外部请求队列中的请求楼层数有大有小,我觉得应该先把楼层数小的请求指令给运行完,然后我就给内部请求和外部请求根据楼层数排序然后再来运行。然后再在和同学的交流中,我才发现原来这两个队列的请求是要一个接着一个来完成的,不能因为后面请求的流程数小而跳过前面的请求,这样就和题目的意思想违背了。以及那个时候我还想把外部请求队列分成两对一个是向上的一个是向下的其实这也是行不通的。是我对电梯运行的逻辑没有搞懂,导致后面的编程出现问题。还有就是假如内部请求的第一个是8楼,外部楼层是5楼向上,这时电梯在1楼,我会觉得应该先到5楼开关门没有考虑到同方向优先,不单单考虑楼层的高低而去判断应该要结合同方向优先的原则进行判断。其实这个题目对我来说比较困难的一点就是下一楼层的判断,因为这个既要结合楼层的高低又要结合同方向优先的原则然后还要分情况讨论if-else如果内部请求和外部请求的第一个请求在电梯所在楼层的上面还是下面有可能都在上面也有可能都在下面也有可能一上一下以及要结合外部楼层的方向进行判断下一步电梯该怎么走,这里判断电梯下一步怎么走还要结合到电梯当前的方向以及楼层来判断,所以说还是有点考验脑力和算法逻辑能力的,我觉得我就是这一步没有做好。 - 反思与进步
这个题目是比较考验算法逻辑的以及对类之间的合作调用,我觉得还有比较大的意义和值得思考的地方。虽然没做出来,但是也让我接触到了复杂的算法是怎么样的,至少我思考了我动手了我觉得我还是有收获的。反思的话,我觉得是自己编程能力还不行,从现在开始没事就看网课打开eclipse敲代码。对今后,我想说多学多做打好基础知识多练,将理论和实践相结合加深学习。我希望在我通过我的不断学习后,我在回过头来看这道题的时候我能半个小时做完然后笑着说这么简单的题目我当时怎么没做出来呢?
2.题目集06单部电梯调度程序(类设计) - 第二次电梯题目查看
点击查看题目
对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类,具体设计可参考如下类图。
电梯运行规则与前阶段单类设计相同,但要处理如下情况:
乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者<5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
注意:本次作业类设计必须符合如上要求(包含但不限于乘客请求类、电梯类、请求队列类及控制类,其中控制类专门负责电梯调度过程),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次电梯程序提交到本次题目中测试)。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。
电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:
运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
输入样例1:
在这里给出一组输入。例如:
1
20
<3,UP>
<5>
<6,DOWN>
<7>
<3>
end
输出样例1:
在这里给出相应的输出。例如:
Current Floor: 1 Direction: UP
Current Floor: 2 Direction: UP
Current Floor: 3 Direction: UP
Open Door # Floor 3
Close Door
Current Floor: 4 Direction: UP
Current Floor: 5 Direction: UP
Open Door # Floor 5
Close Door
Current Floor: 6 Direction: UP
Current Floor: 7 Direction: UP
Open Door # Floor 7
Close Door
Current Floor: 6 Direction: DOWN
Open Door # Floor 6
Close Door
Current Floor: 5 Direction: DOWN
Current Floor: 4 Direction: DOWN
Current Floor: 3 Direction: DOWN
Open Door # Floor 3
Close Door
输入样例2:
在这里给出一组输入。例如:
1
20
<3,UP>
<3,UP>
<5>
<5>
<5>
<6,DOWN>
<7>
<7>
<3>
<22,DOWN>
<5,DOWN>
<30>
END
输出样例2:
在这里给出相应的输出。例如:
Current Floor: 1 Direction: UP
Current Floor: 2 Direction: UP
Current Floor: 3 Direction: UP
Open Door # Floor 3
Close Door
Current Floor: 4 Direction: UP
Current Floor: 5 Direction: UP
Open Door # Floor 5
Close Door
Current Floor: 6 Direction: UP
Current Floor: 7 Direction: UP
Open Door # Floor 7
Close Door
Current Floor: 6 Direction: DOWN
Open Door # Floor 6
Close Door
Current Floor: 5 Direction: DOWN
Open Door # Floor 5
Close Door
Current Floor: 4 Direction: DOWN
Current Floor: 3 Direction: DOWN
Open Door # Floor 3
Close Door

- 题目分析
这次电梯运行规则与前阶段单类设计相同,在上一题的基础添加了一些对乘客请求的处理
- 乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
- 乘客请求不合理,具体为输入时出现连续的相同请求,例如<3><3><3>或者 <5,DOWN><5,DOWN>,处理方法:程序自动忽略相同的多余输入,继续执行,例如<3><3><3>过滤为<3>
这次题目给了类的设计图根据类的设计图去写代码,大概的框架给了剩下的就需要我们去填充自己的逻辑就可以了,其实和第一次的程序大差不差只要再增加点内容就可以了。
- 我的代码
点击查看代码
import java.util.*;
import java.util.LinkedList;
import java.util.Queue;
// 定义电梯运行方向枚举
enum Direction {
UP, DOWN, IDLE
}
// 定义电梯状态枚举
enum State {
MOVING, STOPPED
}
// 定义电梯类(Elevator)
class Elevator {
private int currentFloor;
private Direction direction;
private State state;
private int maxFloor;
private int minFloor;
public Elevator(int minFloor, int maxFloor) {
this.minFloor = minFloor;
this.maxFloor = maxFloor;
this.currentFloor = minFloor;
this.direction = Direction.IDLE;
this.state = State.STOPPED;
}
public int getCurrentFloor() {
return currentFloor;
}
public void setCurrentFloor(int currentFloor) {
this.currentFloor = currentFloor;
}
public Direction getDirection() {
return direction;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public int getMaxFloor() {
return maxFloor;
}
public int getMinFloor() {
return minFloor;
}
// 判断楼层是否有效
public boolean isValidFloor(int floor) {
return floor >= minFloor && floor <= maxFloor;
}
// 电梯移动方法
public void move(int targetFloor) {
if (isValidFloor(targetFloor)) {
if (targetFloor > currentFloor) {
direction = Direction.UP;
state = State.MOVING;
while (currentFloor < targetFloor) {
currentFloor++;
System.out.println("Current Floor: " + currentFloor + " Direction: " + direction);
}
} else if (targetFloor < currentFloor) {
direction = Direction.DOWN;
state = State.MOVING;
while (currentFloor > targetFloor) {
currentFloor--;
System.out.println("Current Floor: " + currentFloor + " Direction: " + direction);
}
}
state = State.STOPPED;
System.out.println("Open Door # Floor " + currentFloor);
System.out.println("Close Door");
}
}
}
// 定义外部乘客请求类(ExternalRequest)
class ExternalRequest {
private Integer floor;
private Direction direction;
public ExternalRequest(Integer floor, Direction direction) {
this.floor = floor;
this.direction = direction;
}
public Integer getFloor() {
return floor;
}
public Direction getDirection() {
return direction;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExternalRequest that = (ExternalRequest) o;
return floor.equals(that.floor) && direction == that.direction;
}
@Override
public int hashCode() {
int result = floor.hashCode();
result = 31 * result + direction.hashCode();
return result;
}
}
// 定义请求队列类(RequestQueue)
class RequestQueue {
private java.util.LinkedList<Integer> internalRequests = new java.util.LinkedList<>();
private java.util.LinkedList<ExternalRequest> externalRequests = new java.util.LinkedList<>();
public RequestQueue getQueueInstance() {
return this;
}
public java.util.LinkedList<Integer> getInternalRequests() {
return internalRequests;
}
public void setInternalRequests(java.util.LinkedList<Integer> internalRequests) {
this.internalRequests = internalRequests;
}
public java.util.LinkedList<ExternalRequest> getExternalRequests() {
return externalRequests;
}
public void setExternalRequests(java.util.LinkedList<ExternalRequest> externalRequests) {
this.externalRequests = externalRequests;
}
// 添加内部请求(电梯内请求)
public void addInternalRequest(int floor, Elevator elevator) {
if (elevator.isValidFloor(floor) &&!internalRequests.contains(floor)) {
internalRequests.add(floor);
}
}
// 添加外部请求(电梯外请求)
public void addExternalRequest(int floor, Direction direction, Elevator elevator) {
ExternalRequest request = new ExternalRequest(floor, direction);
if (elevator.isValidFloor(floor) &&!externalRequests.contains(request)) {
externalRequests.add(request);
}
}
// 对内部请求队列按楼层大小排序
public void sortInternalRequests() {
Collections.sort(internalRequests);
}
// 对外部请求队列按楼层大小排序
public void sortExternalRequests() {
externalRequests.sort(Comparator.comparingInt(ExternalRequest::getFloor));
}
}
// 定义控制类(Controller)
class Controller {
private Elevator elevator;
private RequestQueue queue;
private int minFloor;
public Controller(Elevator elevator, RequestQueue queue,int minFloor) {
this.elevator = elevator;
this.queue = queue;
this.minFloor=minFloor;
}
public Elevator getElevator() {
return elevator;
}
public void setElevator(Elevator elevator) {
this.elevator = elevator;
}
public RequestQueue getQueue() {
return queue;
}
public void setQueue(RequestQueue queue) {
this.queue = queue;
}
// 创建两个队列的方法
public Queue<Integer>[] createTwoQueues() {
Queue<Integer> upQueue = new LinkedList<>();
Queue<Integer> downQueue = new LinkedList<>();
int currentFloor = elevator.getCurrentFloor();
Direction currentDirection = elevator.getDirection();
// 处理内部请求
for (int internalFloor : queue.getInternalRequests()) {
if (currentDirection == Direction.UP && internalFloor > currentFloor) {
upQueue.add(internalFloor);
} else if (currentDirection == Direction.DOWN && internalFloor < currentFloor) {
downQueue.add(internalFloor);
}
}
// 处理外部请求
for (ExternalRequest extReq : queue.getExternalRequests()) {
int extFloor = extReq.getFloor();
Direction extDirection = extReq.getDirection();
if (currentDirection == Direction.UP && extDirection == Direction.UP && extFloor > currentFloor) {
upQueue.add(extFloor);
} else if (currentDirection == Direction.DOWN && extDirection == Direction.DOWN && extFloor < currentFloor) {
downQueue.add(extFloor);
}
}
// 对向上的队列进行从小到大排序
List<Integer> upList = new ArrayList<>(upQueue);
Collections.sort(upList);
upQueue = new LinkedList<>(upList);
// 对向下的队列进行从大到小排序
List<Integer> downList = new ArrayList<>(downQueue);
Collections.sort(downList, Collections.reverseOrder());
downQueue = new LinkedList<>(downList);
Queue<Integer>[] result = new Queue[2];
result[0] = upQueue;
result[1] = downQueue;
return result;
}
// 处理请求方法
public void processRequests() {
java.util.LinkedList<Integer> internal = queue.getInternalRequests();
java.util.LinkedList<ExternalRequest> external = queue.getExternalRequests();
int target = internal.peekFirst();
ExternalRequest extReq = external.peekFirst();
if((target-minFloor)<(extReq.getFloor()-minFloor)){
elevator.move(target);
internal.removeFirst();
}else{
elevator.move(extReq.getFloor());
external.removeFirst();
}
Queue<Integer>[] queues = createTwoQueues();
Queue<Integer> upQueue = queues[0];
Queue<Integer> downQueue = queues[0];
if (elevator.getDirection() == Direction.UP) {
while (!upQueue.isEmpty()) {
int target1 = upQueue.poll();
elevator.move(target1);
}
} else if (elevator.getDirection() == Direction.DOWN) {
while (!downQueue.isEmpty()) {
int target2= downQueue.poll();
elevator.move(target2);
}
}
}
}
// 主类(Main)
public class Main {
public static void main(String[] args) {
java.util.Scanner scanner = new java.util.Scanner(System.in);
int minFloor = scanner.nextInt();
int maxFloor = scanner.nextInt();
scanner.nextLine();
Elevator elevator = new Elevator(minFloor, maxFloor);
RequestQueue queue = new RequestQueue();
Controller controller = new Controller(elevator, queue,minFloor);
String input;
String prevInput = "";
while (!(input = scanner.nextLine()).equalsIgnoreCase("end")) {
if (!input.equals(prevInput)) {
if (input.contains(",")) {
String[] parts = input.split(",");
int floor = Integer.parseInt(parts[0].substring(1));
Direction direction = Direction.valueOf(parts[1].toUpperCase().replace(">", ""));
queue.addExternalRequest(floor, direction, elevator);
} else {
int floor = Integer.parseInt(input.substring(1, input.length() - 1));
queue.addInternalRequest(floor, elevator);
}
prevInput = input;
}
}
System.out.println("Current Floor: 1 Direction: UP");
controller.processRequests();
scanner.close();
}
}
- 代码分析

点击查看代码分析
Metrics Details For File '0601.txt'
--------------------------------------------------------------------------------------------
Parameter Value
========= =====
Project Directory D:\SM\
Project Name Baseline
Checkpoint Name Baseline
File Name 0601.txt
Lines 308
Statements 179
Percent Branch Statements 13.4
Method Call Statements 72
Percent Lines with Comments 6.2
Classes and Interfaces 1
Methods per Class 30.00
Average Statements per Method 5.63
Line Number of Most Complex Method {undefined}
Name of Most Complex Method {no methods}
Maximum Complexity 0
Line Number of Deepest Block 73
Maximum Block Depth 4
Average Block Depth 1.03
Average Complexity 0.00
--------------------------------------------------------------------------------------------
No Methods Found: Complexity
--------------------------------------------------------------------------------------------
Block Depth Statements
0 67
1 73
2 16
3 13
4 10
5 0
6 0
7 0
8 0
9+ 0
--------------------------------------------------------------------------------------------
- 修改后的代码及分析
点击查看代码
import java.util.*;
import java.util.LinkedList;
import java.util.Queue;
// 定义电梯运行方向枚举
enum Direction {
UP, DOWN, IDLE
}
// 定义电梯状态枚举
enum State {
MOVING, STOPPED
}
// 定义电梯类(Elevator)
class Elevator {
private int currentFloor;
private Direction direction;
private State state;
private int maxFloor;
private int minFloor;
public Elevator(int minFloor, int maxFloor) {
this.minFloor = minFloor;
this.maxFloor = maxFloor;
this.currentFloor = minFloor;
this.direction = Direction.IDLE;
this.state = State.STOPPED;
}
public int getCurrentFloor() {
return currentFloor;
}
public void setCurrentFloor(int currentFloor) {
this.currentFloor = currentFloor;
}
public Direction getDirection() {
return direction;
}
public void setDirection(Direction direction) {
this.direction = direction;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public int getMaxFloor() {
return maxFloor;
}
public int getMinFloor() {
return minFloor;
}
// 判断楼层是否有效
public boolean isValidFloor(int floor) {
return floor >= minFloor && floor <= maxFloor;
}
}
// 定义外部乘客请求类(ExternalRequest)
class ExternalRequest {
private Integer floor;
private Direction direction;
public ExternalRequest(Integer floor, Direction direction) {
this.floor = floor;
this.direction = direction;
}
public Integer getFloor() {
return floor;
}
public Direction getDirection() {
return direction;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExternalRequest that = (ExternalRequest) o;
return floor.equals(that.floor) && direction == that.direction;
}
@Override
public int hashCode() {
int result = floor.hashCode();
result = 31 * result + direction.hashCode();
return result;
}
}
// 定义请求队列类(RequestQueue)
class RequestQueue {
private java.util.LinkedList<Integer> internalRequests = new java.util.LinkedList<>();
private java.util.LinkedList<ExternalRequest> externalRequests = new java.util.LinkedList<>();
public RequestQueue getQueueInstance() {
return this;
}
public java.util.LinkedList<Integer> getInternalRequests() {
return internalRequests;
}
public void setInternalRequests(java.util.LinkedList<Integer> internalRequests) {
this.internalRequests = internalRequests;
}
public java.util.LinkedList<ExternalRequest> getExternalRequests() {
return externalRequests;
}
public void setExternalRequests(java.util.LinkedList<ExternalRequest> externalRequests) {
this.externalRequests = externalRequests;
}
// 添加内部请求(电梯内请求)
public void addInternalRequest(int floor, Elevator elevator) {
if (elevator.isValidFloor(floor) &&!internalRequests.contains(floor)) {
internalRequests.add(floor);
}
}
// 添加外部请求(电梯外请求)
public void addExternalRequest(int floor, Direction direction, Elevator elevator) {
ExternalRequest request = new ExternalRequest(floor, direction);
if (elevator.isValidFloor(floor) &&!externalRequests.contains(request)) {
externalRequests.add(request);
}
}
}
// 定义控制类(Controller)
class Controller {
private Elevator elevator;
private RequestQueue queue;
private int minFloor;
public Controller(Elevator elevator, RequestQueue queue,int minFloor) {
this.elevator = elevator;
this.queue = queue;
this.minFloor=minFloor;
}
public Elevator getElevator() {
return elevator;
}
public void setElevator(Elevator elevator) {
this.elevator = elevator;
}
public RequestQueue getQueue() {
return queue;
}
public void setQueue(RequestQueue queue) {
this.queue = queue;
}
// 电梯移动方法
public void move(int targetFloor) {
if (isValidFloor(targetFloor)) {
if (targetFloor > currentFloor) {
direction = Direction.UP;
state = State.MOVING;
while (currentFloor < targetFloor) {
currentFloor++;
System.out.println("Current Floor: " + currentFloor + " Direction: " + direction);
}
} else if (targetFloor < currentFloor) {
direction = Direction.DOWN;
state = State.MOVING;
while (currentFloor > targetFloor) {
currentFloor--;
System.out.println("Current Floor: " + currentFloor + " Direction: " + direction);
}
}
state = State.STOPPED;
System.out.println("Open Door # Floor " + currentFloor);
System.out.println("Close Door");
}
}
public void determineDirection(){
if(internal.isEmpty()&&external.isEmpty()){
elevator.getDirection=Direction.IDLE;
}
if(elevator.getDirection=Direction.UP){
if(internal.isEmpty()){
if(external.First()>currentFloor||!external.First()){
elevator.getDirection=Direction.UP;
}else if(external.First()<currentFloor){
elevator.getDirection=Direction.DOWN;
}
}else if(external.isEmpty()){
if(internal.First()>currentFloor||!internal.First()){
elevator.getDirection=Direction.UP;
}else if(internal.First()<currentFloor){
elevator.getDirection=Direction.DOWN;
}
}else{
if(internal.First()>currentFloor||external.First()>currentFloor){
elevator.getDirection=Direction.UP;
}else if((internal.First()<currentFloor&&external.First()<currentFloor)||(internal.First()==NULL&&external.First<currentFloor)||(external.First()==NULL&&internal.First()<currentFloor)){
elevator.getDirection=Direction.Down;
}else if(internal.First()==NULL&&external.First()=NULL){
elevator.getDirection=Direction.IDLE;
}
}
}else if(elevator.getDirection=Direction.DOWN){
if(internal.isEmpty()){
if(external.First()<currentFloor||!external.First()){
elevator.getDirection=Direction.DOWN;
}else if(external.First()>currentFloor){
elevator.getDirection=Direction.UP;
}
}else if(external.isEmpty()){
if(internal.First()<currentFloor||!internal.First()){
elevator.getDirection=Direction.DOWN;
}else if(internal.First()>currentFloor){
elevator.getDirection=Direction.UP;
}
}else{
if(internal.First()>currentFloor||external.First()>currentFloor){
elevator.getDirection=Direction.UP;
}else if((internal.First()<currentFloor&&external.First()<currentFloor)||(internal.First()==NULL&&external.First<currentFloor)||(external.First()==NULL&&internal.First()<currentFloor)){
elevator.getDirection=Direction.Down;
}else if(internal.First()==NULL&&external.First()=NULL){
elevator.getDirection=Direction.IDLE;
}
}
}
}
public void openDoors(){
if(external.First()==elevator.getCurrentFloor()||internal.First()==elevator.getCurrentFloor()){
System.out.println("Open Door # Floor " + currentFloor);
System.out.println("Close Door");
}
}
public boolean shouldStop(int floor){
if(external.First()==floor||internal.First()==floor){
return true;
}else if(internal.isEmpty()&&external.isEmpty()){
return true;
}else{
return false;
}
}
public Integer getNextFloor(){
java.util.LinkedList<Integer> internal = queue.getInternalRequests();
java.util.LinkedList<ExternalRequest> external = queue.getExternalRequests();
int currentFloor = elevator.getCurrentFloor();
Direction currentDirection = elevator.getDirection();
while(!internal.isEmpty() ||!external.isEmpty()){
ExternalRequest extReq = external.removeFirst();
int target = internal.removeFirst();
if(internal.isEmpty()){
return extReq.getFloor();
}else if(external.isEmpty()){
return target;
}
if(extReq.getDirection()==Direction.UP){
if(extReq.getFloor()>currentFloor&&target>currentFloor){
if(extReq.getFloor()<target){
return extReq.getFloor();
}else{
return target;
}
}else if(target>currentFloor&&extReq.getFloor()<currentFloor){
return target;
}else if(target<currentFloor&&extReq.getFloor()>currentFloor){
return extReq.getFloor();
}else if(target<currentFloor&&extReq.getFloor()<currentFloor){
return target;
}
}else{
if(extReq.getFloor()>currentFloor&&target>currentFloor){
return target;
}else if((extReq.getFloor()>target)&&extReq.getFloor()<currentFloor&&target<currentFloor){
return extReq.getFloor();
}else{
return target;
}
}
}
}
public Integer getClosest(Integer a,Integer b){
int currentFloor = elevator.getCurrentFloor();
if((currentFloor-a)*(currentFloor-a)>(currentFloor-b)*(currentFloor-b)){
return b;
}else{
return a;
}
}
public void removeRequests(int currentFloor){
if(currentFloor==internal.First()){
internal.removeFirst();
}else if(currentFloor==external.First()){
external.removeFirst();
}
}
// 处理请求方法
public void processRequests() {
java.util.LinkedList<Integer> internal = queue.getInternalRequests();
java.util.LinkedList<ExternalRequest> external = queue.getExternalRequests();
int currentFloor = elevator.getCurrentFloor();
Direction currentDirection = elevator.getDirection();
move(getNextFloor);
}
}
// 主类(Main)
public class Main {
public static void main(String[] args) {
java.util.Scanner scanner = new java.util.Scanner(System.in);
int minFloor = scanner.nextInt();
int maxFloor = scanner.nextInt();
scanner.nextLine();
Elevator elevator = new Elevator(minFloor, maxFloor);
RequestQueue queue = new RequestQueue();
Controller controller = new Controller(elevator, queue,minFloor);
String input;
String prevInput = "";
while (!(input = scanner.nextLine()).equalsIgnoreCase("end")) {
if (!input.equals(prevInput)) {
if (input.contains(",")) {
String[] parts = input.split(",");
int floor = Integer.parseInt(parts[0].substring(1));
Direction direction = Direction.valueOf(parts[1].toUpperCase().replace(">", ""));
queue.addExternalRequest(floor, direction, elevator);
} else {
int floor = Integer.parseInt(input.substring(1, input.length() - 1));
queue.addInternalRequest(floor, elevator);
}
prevInput = input;
}
}
System.out.println("Current Floor: 1 Direction: UP");
controller.processRequests();
scanner.close();
}
}
点击查看代码分析
Metrics Details For File '06.txt'
--------------------------------------------------------------------------------------------
Parameter Value
========= =====
Project Directory D:\SM\
Project Name Baseline
Checkpoint Name Baseline
File Name 06.txt
Lines 353
Statements 226
Percent Branch Statements 25.2
Method Call Statements 113
Percent Lines with Comments 3.4
Classes and Interfaces 1
Methods per Class 35.00
Average Statements per Method 6.17
Line Number of Most Complex Method 291
Name of Most Complex Method getClosest().if(()
Maximum Complexity 2
Line Number of Deepest Block 267
Maximum Block Depth 5
Average Block Depth 1.62
Average Complexity 2.00
--------------------------------------------------------------------------------------------
Most Complex Methods in 1 Class(es): Complexity, Statements, Max Depth, Calls
getClosest().if(() 2, 3, 2, 0
--------------------------------------------------------------------------------------------
Block Depth Statements
0 55
1 77
2 28
3 32
4 32
5 2
6 0
7 0
8 0
9+ 0
--------------------------------------------------------------------------------------------

点击查看前后代码对比
代码结构和功能的不同点
Controller 类的功能差异:
第二段代码:Controller 类中包含了更多控制电梯运行和处理请求的方法,如 determineDirection(确定电梯运行方向)、openDoors(控制开门操作并移除已处理请求)、shouldStop(判断电梯是否应在某楼层停靠)、getClosest(获取离当前楼层更近的目标楼层)等。这些方法使得电梯的运行逻辑更加复杂和细致,能够根据不同的请求情况和电梯状态做出更合理的决策。
第一段代码:Controller 类相对简单,除了基本的设置和获取电梯及请求队列的方法外,主要的方法是 createTwoQueues(将请求分为向上和向下两个队列并排序)和 processRequests(根据请求队列和电梯方向处理请求)。在 processRequests 方法中,先比较内部请求和外部请求的第一个元素,选择离最小楼层较近的请求处理,然后根据电梯方向处理相应队列的请求。这种处理逻辑相对直接,没有像第一段代码那样考虑更多的情况。
电梯移动和请求处理逻辑:
第二段代码:move 方法在电梯到达目标楼层后,会调用 removeRequests(currentFloor) 方法移除当前楼层的已处理请求,并且在 processRequests 方法中,通过不断调用 getNextFloor 方法获取下一个目标楼层并移动电梯,getNextFloor 方法会根据电梯当前方向和请求队列情况,选择合适的目标楼层,若当前方向没有合适楼层则切换方向重新查找。
第一段代码:move 方法只是简单地根据目标楼层和当前楼层的关系,更新电梯的方向和状态并移动电梯,到达目标楼层后打印开门和关门信息,但没有移除请求的操作。在 processRequests 方法中,先处理内部请求和外部请求的第一个元素,然后根据电梯方向处理相应队列的请求,没有像第一段代码那样动态地选择下一个目标楼层。
方法和变量的细节差异:
变量定义:第一段代码的 Controller 类中定义了 minFloor 和 maxFloor 变量来记录楼层范围,而第二段代码只定义了 minFloor 变量,maxFloor 变量在 Elevator 类中设置和获取。
方法实现:例如在处理请求队列排序时,第一段代码的 RequestQueue 类没有对请求队列进行排序的方法,而第二段代码有 sortInternalRequests 和 sortExternalRequests 方法分别对内部请求队列和外部请求队列按楼层大小进行排序。
| 对比项 | 代码二(06.txt) | 代码一(0601.txt) |
|---|---|---|
| 代码行数 | 353 行 | 308 行 |
| 语句数量(Statements) | 226 条 | 179 条 |
| 分支语句比例(Percent Branch Statements) | 25.2% | 13.4% |
| 方法调用语句数量(Method Call Statements) | 113 条 | 72 条 |
| 注释行比例(Percent Lines with Comments) | 3.4% | 6.2% |
| 类和接口数量(Classes and Interfaces) | 1 个 | 1 个 |
| 每个类的方法数量(Methods per Class) | 35.00 个 | 30.00 个 |
| 每个方法的平均语句数(Average Statements per Method) | 6.17 条 | 5.63 条 |
| 最复杂方法的行号(Line Number of Most Complex Method) | 291 行 | |
| 最复杂方法的名称(Name of Most Complex Method) | getClosest().if(() | |
| 最大复杂度(Maximum Complexity) | 2 | 0 |
| 最深代码块的行号(Line Number of Deepest Block) | 267 行 | 73 行 |
| 最大代码块深度(Maximum Block Depth) | 5 | 4 |
| 平均代码块深度(Average Block Depth) | 1.62 | 1.03 |
| 平均复杂度(Average Complexity) | 2.00 | 0.00 |
| Controller 类中 move 方法 | 内部通过 isValidFloor 判断楼层有效性,根据目标楼层与当前楼层关系改变方向和状态并移动电梯,到达后打印开关门信息,但未移除请求相关操作(方法内直接使用了类的成员变量 direction、state、currentFloor 等,没有通过 elevator 对象的方法获取或设置) | 先检查目标楼层在有效范围(targetFloor >= minFloor && targetFloor <= maxFloor),根据目标楼层与当前楼层关系改变 elevator 的方向和状态并移动电梯,到达后打印开关门信息,且调用 removeRequests(currentFloor) 移除当前楼层的已处理请求 |
| Controller 类中 determineDirection 方法 | 存在多处语法错误(如 elevator.getDirection=Direction.IDLE; 应是 elevator.setDirection(Direction.IDLE); 等),逻辑是根据内外部请求队列是否为空以及请求楼层与当前楼层关系确定电梯方向 | 逻辑是根据内外部请求队列是否为空以及请求楼层与当前楼层关系确定电梯方向,代码相对更完整正确,没有明显语法错误 |
| Controller 类中 openDoors 方法 | 存在语法错误(如 external.First() 等,LinkedList 没有 First 方法,应该是 peekFirst 等),逻辑是当外部请求或内部请求的第一个元素楼层等于当前楼层时,打印开关门信息 | 逻辑是当外部请求的第一个元素楼层等于当前楼层 或者 内部请求的第一个元素等于当前楼层时,打印开关门信息,并且调用 removeRequests(currentFloor) 移除已处理请求 |
| Controller 类中 shouldStop 方法 | 存在语法错误(如 external.First() 等),逻辑是当外部请求或内部请求的第一个元素楼层等于指定楼层,或者内外部请求队列为空时,返回 true,否则返回 false | 逻辑是当外部请求的第一个元素楼层等于指定楼层 或者 内部请求的第一个元素等于指定楼层,或者内外部请求队列为空时,返回 true,否则返回 false |
| Controller 类中 getNextFloor 方法 | 逻辑较为复杂,先获取内外部请求队列,在一个 while 循环中处理请求队列,根据请求方向和楼层与当前楼层关系选择下一个目标楼层,存在语法错误(如 ExternalRequest extReq = external.removeFirst(); 直接移除元素可能不符合预期逻辑,一般先 peek 查看再决定是否移除等) | 逻辑是根据电梯当前方向和请求队列情况,选择合适的目标楼层,若当前方向没有合适楼层则切换方向重新查找,代码相对更简洁且没有明显语法错误 |
| Controller 类中 getClosest 方法 | 实现了获取离当前楼层更近的楼层(a 和 b 两个楼层比较)的功能,通过比较楼层与当前楼层差值的平方来判断 | 实现了类似功能,通过比较楼层与当前楼层差值的平方来判断离当前楼层更近的楼层,但在第一段代码分析中被标记为最复杂方法 |
| Controller 类中 removeRequests 方法 | 存在语法错误(如 currentFloor==internal.First() 应是 currentFloor == internal.peekFirst() 等),逻辑是当当前楼层等于内部请求或外部请求的第一个元素楼层时,移除相应请求 | 逻辑是当外部请求的第一个元素的楼层等于当前楼层,移除该外部请求;当内部请求的第一个元素等于当前楼层,移除该内部请求 |
| Controller 类中 processRequests 方法 | 先获取内外部请求队列和当前楼层、方向,调用 move(getNextFloor)(这里 getNextFloor 调用方式错误,应该是 move(getNextFloor())),逻辑存在问题且有语法错误 | 先比较内部请求和外部请求的第一个元素,选择离最小楼层较近的请求处理,然后根据电梯方向处理相应队列的请求(通过 createTwoQueues 方法得到两个队列),逻辑相对清晰且没有明显语法错误 |
| RequestQueue 类 | 包含添加内外部请求方法,无请求队列排序方法 | 包含添加内外部请求方法,还有 sortInternalRequests 和 sortExternalRequests 方法分别对内部请求队列和外部请求队列按楼层大小进行排序 |
| 不合理请求处理(楼层数有误) | 在 RequestQueue 类的 addInternalRequest 和 addExternalRequest 方法中,通过调用 elevator.isValidFloor(floor) 检查楼层有效性,若无效则忽略请求 | 在 RequestQueue 类的 addInternalRequest 和 addExternalRequest 方法中,通过调用 elevator.isValidFloor(floor) 检查楼层有效性,若无效则忽略请求 |
| 不合理请求处理(连续相同请求) | 在 Main 类中通过比较当前输入和上一次输入(prevInput),实现了对连续相同请求的过滤 | 在 Main 类中通过比较当前输入和上一次输入(prevInput),实现了对连续相同请求的过滤 |
- 挫折与心路历程
这题我其实和第一次电梯程序错的差不多,也是因为第二次作业和第一次相差不大,主要是因为我第一次作业没写出来没有懂电梯运行的逻辑。上面展示的代码是我自己第一次做的时候自己写的,逻辑错误还是挺明显的。在上面的代码里,我把内外请求进行排序,当时自己做了挺久结果南辕北辙,所以说先搞定题目再去做不然的话就是在浪费时间。 - 反思与进步
我觉得我没有真正的搞懂他,然后也看见了自己和其他同学的差距越来越大。因为之前的题目集,难度没有这么大所以很那拉开差距,大家都是第一名都是满分。现在,经过了前两次的电梯程序我觉得我至少学到了些类之间的调用来实现一个整体的功能
3.题目集07单部电梯调度程序(类设计-迭代) - 第三次电梯题目查看
点击查看题目
对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,具体设计可参考类图。
电梯运行规则与前阶段相同,但有如下变动情况:
乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
注意:本次作业类设计必须符合如上要求(包含但不限于设计电梯类、乘客类、队列类以及控制类),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次及第二次电梯程序提交到本次题目中测试)。
输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。
电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<请求源楼层,请求目的楼层>,其中,请求源楼层表示乘客发起请求所在的楼层,请求目的楼层表示乘客想要到达的楼层。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:
运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door
输入样例1:
在这里给出一组输入。例如:
1
20
<5,4>
<5>
<7>
end
输出样例1:
在这里给出相应的输出。例如:
Current Floor: 1 Direction: UP
Current Floor: 2 Direction: UP
Current Floor: 3 Direction: UP
Current Floor: 4 Direction: UP
Current Floor: 5 Direction: UP
Open Door # Floor 5
Close Door
Current Floor: 6 Direction: UP
Current Floor: 7 Direction: UP
Open Door # Floor 7
Close Door
Current Floor: 6 Direction: DOWN
Current Floor: 5 Direction: DOWN
Open Door # Floor 5
Close Door
Current Floor: 4 Direction: DOWN
Open Door # Floor 4
Close Door
输入样例2:
在这里给出一组输入。例如:
1
20
<5,9>
<8>
<9,3>
<4>
<2>
end
输出样例2:
在这里给出相应的输出。例如:
Current Floor: 1 Direction: UP
Current Floor: 2 Direction: UP
Current Floor: 3 Direction: UP
Current Floor: 4 Direction: UP
Current Floor: 5 Direction: UP
Open Door # Floor 5
Close Door
Current Floor: 6 Direction: UP
Current Floor: 7 Direction: UP
Current Floor: 8 Direction: UP
Open Door # Floor 8
Close Door
Current Floor: 9 Direction: UP
Open Door # Floor 9
Close Door
Current Floor: 8 Direction: DOWN
Current Floor: 7 Direction: DOWN
Current Floor: 6 Direction: DOWN
Current Floor: 5 Direction: DOWN
Current Floor: 4 Direction: DOWN
Open Door # Floor 4
Close Door
Current Floor: 3 Direction: DOWN
Current Floor: 2 Direction: DOWN
Open Door # Floor 2
Close Door
Current Floor: 3 Direction: UP
Current Floor: 4 Direction: UP
Current Floor: 5 Direction: UP
Current Floor: 6 Direction: UP
Current Floor: 7 Direction: UP
Current Floor: 8 Direction: UP
Current Floor: 9 Direction: UP
Open Door # Floor 9
Close Door
Current Floor: 8 Direction: DOWN
Current Floor: 7 Direction: DOWN
Current Floor: 6 Direction: DOWN
Current Floor: 5 Direction: DOWN
Current Floor: 4 Direction: DOWN
Current Floor: 3 Direction: DOWN
Open Door # Floor 3
Close Door

- 题目分析
电梯运行规则与前阶段相同,但有如下变动情况:
1.乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
2.对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
这次没有直接告诉你外部请求的方向,这需要你去判断用外部请求的请求源楼层和请求目的楼层请求目标楼层进行比较来确定方向
题目三因为乘客请求的变化导致了类的变化 - 我的代码
点击查看代码
import java.util.*;
class Main {
private static final int MIN_FLOOR = 1; // 楼层最小值
private static final int MAX_FLOOR = 20; // 楼层最大值
// 定义电梯运行方向的枚举类型
private enum Direction {
UP, DOWN, IDLE // 向上,向下,空闲(无方向)
}
// 定义请求类,表示单个电梯请求
private static class Request {
int floor; // 请求的楼层
Direction direction; // 请求的方向(仅外部请求有方向)
Request(int floor, Direction direction) {
this.floor = floor;
this.direction = direction;
}
}
// 定义电梯类,包含电梯的状态和行为
private static class Elevator {
int currentFloor = 1; // 当前楼层,初始为1楼
Direction direction = Direction.IDLE; // 当前方向,初始为空闲
boolean isMoving = false; // 电梯是否正在移动
// 向上移动一层
void moveUp() {
currentFloor++;
direction = Direction.UP;
}
// 向下移动一层
void moveDown() {
currentFloor--;
direction = Direction.DOWN;
}
// 停止移动
void stop() {
isMoving = false;
direction = Direction.IDLE;
}
// 开门
void openDoor() {
System.out.println("Open Door # Floor " + currentFloor);
}
// 关门
void closeDoor() {
System.out.println("Close Door");
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 定义外部请求队列(OuterQueue)和内部请求队列(InnerQueue)
List<Request> outerQueue = new LinkedList<>(); // 外部请求队列,按顺序存储外部请求
Queue<Integer> innerQueue = new LinkedList<>(); // 内部请求队列,按顺序存储内部请求
System.out.println("Enter elevator requests (end to finish):");
// 输入解析
while (scanner.hasNext()) {
String input = scanner.nextLine();
if (input.equals("end")) break; // 输入结束标志
if (input.startsWith("<") && input.contains(",")) {
// 外部请求格式为 <楼层,方向>
String[] parts = input.substring(1, input.length() - 1).split(",");
int floor = Integer.parseInt(parts[0]);
Direction direction = parts[1].equals("UP") ? Direction.UP : Direction.DOWN;
outerQueue.add(new Request(floor, direction)); // 添加到外部请求队列
} else if (input.startsWith("<") && !input.contains(",")) {
// 内部请求格式为 <楼层>
int floor = Integer.parseInt(input.substring(1, input.length() - 1));
innerQueue.add(floor); // 添加到内部请求队列
}
}
// 创建电梯对象
Elevator elevator = new Elevator();
// 模拟电梯运行
while (!outerQueue.isEmpty() || !innerQueue.isEmpty()) {
// 确定下一个目标楼层和方向
Integer nextInnerFloor = innerQueue.peek(); // 内部请求的第一个目标楼层
Request nextOuterRequest = !outerQueue.isEmpty() ? outerQueue.get(0) : null; // 外部请求的第一个目标楼层
int nextTargetFloor = -1; // 下一个目标楼层
Direction nextDirection = Direction.IDLE; // 下一个运行方向
if (nextInnerFloor != null) {
// 如果内部请求不为空,优先处理内部请求
nextTargetFloor = nextInnerFloor;
nextDirection = nextTargetFloor > elevator.currentFloor ? Direction.UP : Direction.DOWN;
}
if (nextOuterRequest != null) {
// 如果外部请求存在,比较外部请求和内部请求的优先级
if (nextTargetFloor == -1 || Math.abs(nextOuterRequest.floor - elevator.currentFloor) <
Math.abs(nextTargetFloor - elevator.currentFloor)) {
nextTargetFloor = nextOuterRequest.floor;
nextDirection = nextOuterRequest.floor > elevator.currentFloor ? Direction.UP : Direction.DOWN;
}
}
if (nextTargetFloor == -1) {
// 如果没有目标楼层,则电梯停止
elevator.stop();
break;
}
// 电梯移动
if (elevator.currentFloor < nextTargetFloor) {
elevator.moveUp();
} else if (elevator.currentFloor > nextTargetFloor) {
elevator.moveDown();
}
// 打印当前楼层和方向
System.out.println("当前楼层:" + elevator.currentFloor + ",方向:" + elevator.direction);
// 检查是否需要在当前楼层停下处理请求
if (elevator.currentFloor == nextTargetFloor) {
elevator.stop(); // 停止电梯
elevator.openDoor(); // 开门
// 移除已处理的请求
if (nextInnerFloor != null && nextInnerFloor == elevator.currentFloor) {
innerQueue.poll(); // 移除内部请求
}
if (nextOuterRequest != null && nextOuterRequest.floor == elevator.currentFloor) {
outerQueue.remove(0); // 移除外部请求
}
elevator.closeDoor(); // 关门
}
}
// 所有请求处理完毕,电梯停止
System.out.println("电梯已停止,所有请求已处理完成。");
}
}
- 分析
点击查看代码分析
Metrics Details For File '0705.txt'
--------------------------------------------------------------------------------------------
Parameter Value
========= =====
Project Directory D:\SM\
Project Name Baseline
Checkpoint Name Baseline
File Name 0705.txt
Lines 148
Statements 60
Percent Branch Statements 21.7
Method Call Statements 28
Percent Lines with Comments 26.4
Classes and Interfaces 3
Methods per Class 1.33
Average Statements per Method 11.50
Line Number of Most Complex Method 11
Name of Most Complex Method Request.Request()
Maximum Complexity 1
Line Number of Deepest Block 90
Maximum Block Depth 5
Average Block Depth 2.43
Average Complexity 1.00
--------------------------------------------------------------------------------------------
Most Complex Methods in 1 Class(es): Complexity, Statements, Max Depth, Calls
Request.Request() 1, 2, 3, 0
--------------------------------------------------------------------------------------------
Block Depth Statements
0 6
1 12
2 11
3 16
4 11
5 4
6 0
7 0
8 0
9+ 0
--------------------------------------------------------------------------------------------

- 修改后的代码及分析
点击查看修改后的代码
import java.util.*;
// 乘客类
class Passenger {
private int sourceFloor;
private int destinationFloor;
public Passenger(int sourceFloor, int destinationFloor) {
this.sourceFloor = sourceFloor;
this.destinationFloor = destinationFloor;
}
public int getSourceFloor() {
return sourceFloor;
}
public int getDestinationFloor() {
return destinationFloor;
}
}
// 队列类
class RequestQueue {
private Queue<Integer> internalRequests;
private Queue<Passenger> externalRequests;
public RequestQueue() {
internalRequests = new LinkedList<>();
externalRequests = new LinkedList<>();
}
public void addInternalRequest(int floor) {
if (!internalRequests.contains(floor)) {
internalRequests.add(floor);
}
}
public void addExternalRequest(Passenger passenger) {
externalRequests.add(passenger);
}
public Queue<Integer> getInternalRequests() {
return internalRequests;
}
public Queue<Passenger> getExternalRequests() {
return externalRequests;
}
}
// 电梯类
class Elevator {
private int currentFloor;
private int minFloor;
private int maxFloor;
private int direction; // 1 表示向上,-1 表示向下
private RequestQueue requestQueue;
public Elevator(int minFloor, int maxFloor) {
this.currentFloor = minFloor;
this.minFloor = minFloor;
this.maxFloor = maxFloor;
this.direction = 1;
this.requestQueue = new RequestQueue();
// 输出初始位置
System.out.println("Current Floor: " + currentFloor + " Direction: UP");
}
public int getCurrentFloor() {
return currentFloor;
}
public void addInternalRequest(int floor) {
requestQueue.addInternalRequest(floor);
}
public void addExternalRequest(Passenger passenger) {
requestQueue.addExternalRequest(passenger);
}
public void run() {
while (!requestQueue.getExternalRequests().isEmpty() || !requestQueue.getInternalRequests().isEmpty()) {
// 优先处理同方向的请求
boolean hasRequest = false;
if (direction == 1) {
hasRequest = handleUpRequests();
} else {
hasRequest = handleDownRequests();
}
if (!hasRequest) {
// 没有同方向的请求,改变方向
direction = -direction;
}
}
}
private boolean handleUpRequests() {
boolean hasRequest = false;
// 处理外部向上请求
Iterator<Passenger> externalIterator = requestQueue.getExternalRequests().iterator();
while (externalIterator.hasNext()) {
Passenger passenger = externalIterator.next();
int sourceFloor = passenger.getSourceFloor();
if (sourceFloor >= currentFloor) {
moveToFloor(sourceFloor);
System.out.println("Open Door # Floor " + sourceFloor);
System.out.println("Close Door");
externalIterator.remove();
requestQueue.addInternalRequest(passenger.getDestinationFloor());
hasRequest = true;
}
}
// 处理内部向上请求
Iterator<Integer> internalIterator = requestQueue.getInternalRequests().iterator();
while (internalIterator.hasNext()) {
int nextFloor = internalIterator.next();
if (nextFloor >= currentFloor) {
moveToFloor(nextFloor);
System.out.println("Open Door # Floor " + nextFloor);
System.out.println("Close Door");
internalIterator.remove();
hasRequest = true;
}
}
return hasRequest;
}
private boolean handleDownRequests() {
boolean hasRequest = false;
// 处理外部向下请求
Iterator<Passenger> externalIterator = requestQueue.getExternalRequests().iterator();
while (externalIterator.hasNext()) {
Passenger passenger = externalIterator.next();
int sourceFloor = passenger.getSourceFloor();
if (sourceFloor <= currentFloor) {
moveToFloor(sourceFloor);
System.out.println("Open Door # Floor " + sourceFloor);
System.out.println("Close Door");
externalIterator.remove();
requestQueue.addInternalRequest(passenger.getDestinationFloor());
hasRequest = true;
}
}
// 处理内部向下请求
Iterator<Integer> internalIterator = requestQueue.getInternalRequests().iterator();
while (internalIterator.hasNext()) {
int nextFloor = internalIterator.next();
if (nextFloor <= currentFloor) {
moveToFloor(nextFloor);
System.out.println("Open Door # Floor " + nextFloor);
System.out.println("Close Door");
internalIterator.remove();
hasRequest = true;
}
}
return hasRequest;
}
private void moveToFloor(int targetFloor) {
if (targetFloor > currentFloor) {
direction = 1;
while (currentFloor < targetFloor) {
currentFloor++;
System.out.println("Current Floor: " + currentFloor + " Direction: UP");
}
} else if (targetFloor < currentFloor) {
direction = -1;
while (currentFloor > targetFloor) {
currentFloor--;
System.out.println("Current Floor: " + currentFloor + " Direction: DOWN");
}
}
}
}
// 控制类
class ElevatorController {
private Elevator elevator;
public ElevatorController(int minFloor, int maxFloor) {
this.elevator = new Elevator(minFloor, maxFloor);
}
public void handleRequest(String request) {
if (request.startsWith("<") && request.endsWith(">")) {
request = request.substring(1, request.length() - 1);
if (request.contains(",")) {
String[] parts = request.split(",");
int sourceFloor = Integer.parseInt(parts[0]);
int destinationFloor = Integer.parseInt(parts[1]);
elevator.addExternalRequest(new Passenger(sourceFloor, destinationFloor));
} else {
int floor = Integer.parseInt(request);
elevator.addInternalRequest(floor);
}
}
}
public void startElevator() {
elevator.run();
}
}
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int minFloor = scanner.nextInt();
int maxFloor = scanner.nextInt();
scanner.nextLine(); // 消耗掉换行符
ElevatorController controller = new ElevatorController(minFloor, maxFloor);
String line;
while (scanner.hasNextLine()) {
line = scanner.nextLine().trim();
if ("end".equalsIgnoreCase(line)) {
break;
}
controller.handleRequest(line);
}
controller.startElevator();
scanner.close();
}
}
点击查看修改后的代码分析
Metrics Details For File '0708.txt'
--------------------------------------------------------------------------------------------
Parameter Value
========= =====
Project Directory D:\SM\
Project Name Baseline
Checkpoint Name Baseline
File Name 0708.txt
Lines 224
Statements 137
Percent Branch Statements 16.1
Method Call Statements 66
Percent Lines with Comments 5.8
Classes and Interfaces 1
Methods per Class 20.00
Average Statements per Method 6.65
Line Number of Most Complex Method 199
Name of Most Complex Method Main.main()
Maximum Complexity 3
Line Number of Deepest Block 82
Maximum Block Depth 3
Average Block Depth 1.54
Average Complexity 3.00
--------------------------------------------------------------------------------------------
Most Complex Methods in 1 Class(es): Complexity, Statements, Max Depth, Calls
Main.main() 3, 12, 3, 9
--------------------------------------------------------------------------------------------
Block Depth Statements
0 31
1 38
2 31
3 37
4 0
5 0
6 0
7 0
8 0
9+ 0
--------------------------------------------------------------------------------------------

- 修改前后两次代码比较分析
| 对比项 | 修改前 | 修改后 |
|---|---|---|
| 代码行数(Lines) | 148 行 | 224 行 |
| 语句数量(Statements) | 60 条 | 137 条 |
| 分支语句比例(Percent Branch Statements) | 21.7% | 16.1% |
| 方法调用语句数量(Method Call Statements) | 28 条 | 66 条 |
| 注释行比例(Percent Lines with Comments) | 26.4% | 5.8% |
| 类和接口数量(Classes and Interfaces) | 3 个 | 1 个(但实际包含多个类,可能统计方式不同) |
| 每个类的方法数量(Methods per Class) | 1.33 个 | 20.00 个 |
| 每个方法的平均语句数(Average Statements per Method) | 11.50 条 | 6.65 条 |
| 最复杂方法的行号(Line Number of Most Complex Method) | 11 行 | 199 行 |
| 最复杂方法的名称(Name of Most Complex Method) | Request.Request() | Main.main() |
| 最大复杂度(Maximum Complexity) | 1 | 3 |
| 最深代码块的行号(Line Number of Deepest Block) | 90 行 | 82 行 |
| 最大代码块深度(Maximum Block Depth) | 5 | 3 |
| 平均代码块深度(Average Block Depth) | 2.43 | 1.54 |
| 平均复杂度(Average Complexity) | 1.00 | 3.00 |
| 请求处理策略 | 优先内部请求,比较外部请求和内部请求与当前楼层距离选择目标楼层 | 优先处理同方向的外部请求,再处理同方向内部请求,无同方向请求则改变方向 |
| 电梯移动方式 | 每次移动一层,根据目标楼层和当前楼层关系确定方向 | 直接移动到目标楼层,根据目标楼层和当前楼层关系确定方向 |
| 类的职责划分 | Main 类承担较多逻辑,其他类职责相对简单 | 职责划分明确,Elevator、RequestQueue、ElevatorController 和 Passenger 各司其职 |
代码逻辑区别
1.请求处理逻辑:
0705.txt:外部请求使用 List
0708.txt:外部请求使用 Queue
2.电梯运行逻辑:
0705.txt:电梯通过 moveUp 和 moveDown 方法每次移动一层,根据目标楼层和当前楼层的关系确定移动方向。到达目标楼层后停止电梯,开门,移除已处理的请求,然后关门。
0708.txt:电梯通过 moveToFloor 方法移动到目标楼层,在移动过程中根据目标楼层和当前楼层的关系确定方向(1 表示向上,-1 表示向下)。在处理请求时,会先处理同方向的请求,处理完后再根据情况改变方向。
3.类的职责和协作:
0705.txt:Main 类承担了大部分的逻辑处理,包括输入解析、请求队列管理、电梯运行控制等。Elevator 类主要负责电梯的基本操作(移动、开关门等),Request 类表示请求。
0708.txt:代码的职责划分更明确。Elevator 类负责电梯的状态管理和运行逻辑;RequestQueue 类负责管理内外部请求队列;ElevatorController 类负责接收请求并将其添加到电梯的请求队列中,以及启动电梯。Passenger 类表示乘客请求。
- 挫折与心路历程
做的时候我觉得被复杂的类之间的关系以及电梯运行的逻辑给弄糊涂了,所以我觉得在做题的时候应该冷静头脑,有时候拿出纸和笔在纸上演示一下电梯运行逻辑对后面的解答会有帮助的,然后在开始敲代码之前先画好类的设计图以及类之间的关系构思好这样在敲代码的时候逻辑清晰脑子也不会乱了,也提高了效率和速度,也方便后面回过头来查找错误。不要单纯的就盯着电脑扣代码,试着想解一个数学题目一样去做可能会有不一样的感觉。 - 反思与进步
不要惧怕失败,发现自己的不足然后去成长和进步
三.总结
第一次实际上就是单类设计,考虑算法,第二次根据面向对象的单一职责设计原则进行多个类的设计以及类间协作,增加控制类,实际上遵循了面向对象设计中的迪米特法则,降低耦合。第四次是用户需求增加导致类的变化。



浙公网安备 33010602011771号