NCHU_单部电梯调度程序

                                  NCHU_单部电梯调度程序

 一、前言

1.三次题目的概述分析

          题目一为单部电梯调度基础系统,要求实现的主要内容为:电梯系统可以响应内部乘客请求和外部乘客请求并合理处理。最核心的难点在于如何理解并实现电梯同向优先的调度规则,即当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。这一规则就需要我们处理好内部请求队列、外部请求队列和电梯当前运行状态的关系。

          题目二为对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),将原来单一的电梯类按职责划分为电梯类、乘客请求类、队列类以及控制类,同时加入了自动过滤重复请求的功能。

          题目三为对之前电梯调度程序再次进行迭代性设计,让程序跟接近真实生活情况,要求加入乘客类(Passenger),取消乘客请求类。乘客请求输入发生变动,外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>。

          三次作业围绕电梯调度主题,层层推进,不断迭代优化。其中个人认为作业一的难度相对较大,地位也相对重要,我们需要从零开始构建,规划出合理的框架方便后续的迭代优化。

 

 二、设计与分析

1.第一次作业

(1)题目:

       设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为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

(2)类的设计

     考虑到后续的迭代,我并没有将电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列这些属性方法放入一个类,这样虽然在使用各种变量时很方便,减少了代码量,但是代码显得十分“臃肿”,可读性很差,可扩展性几乎没有,实在是得不偿失。于是,我按照职责初步划分为了电梯类、队列类和电梯系统控制类。但是,又考虑到电梯运行状态不仅仅是一个标识符,更是电梯调度时一个重要的判断条件,所以我将电梯状态、状态从电梯类中划出来单独设计了一个类LIftState。

     接着,我对如何定义电梯状态、方向的类型犯起了愁,最开始我使用String[]数组用于存储它们:

查看代码
class LiftState {
    private String[] runDirection; // 运行方向: "UP", "DOWN", "IDLE"
    private String[] runState;     // 运行状态: "STOPPED", "MOVING", "OPENING", "CLOSING"

    public LiftState() {
        runDirection = new String[]{"IDLE"};
        runState = new String[]{"STOPPED"};
    }
    }

       但是在实际应用时电梯状态和方向在处理内外队列请求时,取值范围会频繁变动,而String是“常量”字符串,一旦字符串拼写错误,需要手动修改所有相关的字符串判断逻辑(如 if (state.equals("OPENING"))),导致编写代码费事费力。在查阅资料后,我选择了更适合的enum枚举类型。

查看代码
enum Direction {
    UP, DOWN, IDLE
}

enum State {
    MOVING, STOPPED
}

class LiftState {//电梯状态类
    private State lstate = State.STOPPED;
    private Direction ldirection = Direction.IDLE;
    ......
}

  枚举值是自解释的,代码中直接使用 Direction.UP 比字符串 "UP" 更直观,读者能立即明确其含义,无需查看字符串数组的定义。枚举值是单例的(每个枚举值在内存中只存在一个实例),创建后不会重复分配内存,性能稳定。

  最后,根据题目我设计出了如下类图:

未命名绘图.drawio

(3)“同向优先”--LOOK算法

     为处理好内部请求队列、外部请求队列和电梯当前运行状态的关系,我定义了一个processRequest()方法,代码主要框架如下:

查看代码
    public void processRequest() {
        // 无限循环处理请求,直到所有请求为空时退出
        while (true) {
            // 场景1:无任何请求(内部+外部请求都为空)- 处理完成,退出循环
            if (requestList.getInternalRequests().isEmpty() && requestList.getExternalRequests().isEmpty()) {
                elevator.setDirection(Direction.IDLE); // 电梯设为空闲状态
                return;
            }

            // 场景2:只有外部请求(内部请求为空)
            else if (requestList.getInternalRequests().isEmpty()) {
                // 计算外部请求的目标楼层
                int exFloor = calculateFloor();
               //方法同上......
            }

            // 场景3:只有内部请求(外部请求为空)
            else if (requestList.getExternalRequests().isEmpty()) {
                // 获取首个内部请求的目标楼层(内部请求按队列顺序处理)
                int inFloor = requestList.getInternalRequests().get(0);
                // 移动电梯到内部请求楼层(直到当前楼层=目标楼层)
                //方法同上......
            }

            // 场景4:同时存在内部请求和外部请求(核心复杂逻辑)
            else {
                

                // 内部请求楼层 和 外部请求楼层 都在当前楼层的上方(同向:向上)
                if (inFloor >= elevator.getCurFloor() && exFloor >= elevator.getCurFloor()) {
                    elevator.setDirection(Direction.UP); // 统一设置方向为向上

                    // 子子场景4.1.1:外部请求是"向上呼梯"(UP)
                    if (exDir.equals("UP")) {
                        if (inFloor > exFloor) { // 内部目标楼层 > 外部呼梯楼层:优先响应更近的外部请求
                            while (exFloor != elevator.getCurFloor()) {
                                move(); // 移动到外部请求楼层
                            }
                            openDoor();
                            closeDoor();
                            requestList.removeExternalRequest(); // 移除已处理的外部请求
                        } else if (inFloor < exFloor) { // 内部目标楼层 < 外部呼梯楼层:优先响应更近的内部请求
                           ......
                        } else { // 内部和外部请求在同一楼层:同时响应
                        ......
                        }
                    }

                    // 外部请求是"向下呼梯"(DOWN)
                    else if (exDir.equals("DOWN")) {
                       ......
                    }
                }

                // 内部请求楼层 和 外部请求楼层 都在当前楼层的下方(同向:向下)
                else if (inFloor < elevator.getCurFloor() && exFloor < elevator.getCurFloor()) {
                    elevator.setDirection(Direction.DOWN); 

                    // 外部请求是"向下呼梯"(DOWN)
                    if (exDir.equals("DOWN")) {
                        ......
                        } else if (inFloor < exFloor) { // 内部目标楼层 < 外部呼梯楼层:优先响应更近的外部请求
                           ......
                        } else { // 内部和外部请求在同一楼层:同时响应
                           ......
                            }
                            ......
                        }
                    }

                    // 外部请求是"向上呼梯"(UP)
                    else if (exDir.equals("UP")) {
                        ......
                    }
                }

                // 内部请求和外部请求在当前楼层的不同方向(异向)
                else {
                    if (exFloor > inFloor) { // 外部请求楼层在上方,内部请求楼层在下方(异向)
                        // 按电梯当前方向优先响应
                        ......
                        } else if (elevator.getDirection().equals(Direction.DOWN)) { // 当前方向向下:优先响应下方的内部请求
                            ......
                        }
                    } else { // 外部请求楼层在下方,内部请求楼层在上方(异向)
                        // 按电梯当前方向优先响应
                        if (elevator.getDirection().equals(Direction.UP)) { // 当前方向向上:优先响应上方的内部请求
                           ......
                        } else if (elevator.getDirection().equals(Direction.DOWN)) { // 当前方向向下:优先响应下方的外部请求
                            ......
                            }
                           ......
                            // 若外部请求是向上呼梯,处理后切换方向为向上
                            if (exDir.equals(Direction.UP.name())) {
                              ......
                            }
                            ......
                        }
                    }
                }
            }
        }
    }

    // 移动电梯一层
    private void move() {
        int cur = elevator.getCurFloor();
        if (elevator.getDirection().equals(Direction.UP)) {
            elevator.setCurFloor(cur + 1);
        } else {
            elevator.setCurFloor(cur - 1);
        }
        System.out.printf("移动到楼层:%d,方向:%s%n", elevator.getCurFloor(), elevator.getDirection());
    }

    //电梯开门
    private void openDoor() {
        System.out.printf("电梯在楼层 %d 开门%n", elevator.getCurFloor());
    }

    // 电梯关门
    private void closeDoor() {
        System.out.println("电梯关门");
    }

    // 解析外部请求的目标楼层
    private int calculateFloor() {
       
    }
}

  上述代码虽然可以正确处理内部请求队列、外部请求队列和电梯当前运行状态的关系,但是加入了太多if-else if语句导致编写的时候十分复杂,且代码中有很多相同结构,可读性很差,也很容易弄混以及发生运行超时的情况。

image

  为此,我进行了优化保持原有的结构,将if语句划分为不同函数:

查看代码
if (内部请求空 && 外部请求空) → 结束
else if (内部请求空) → 处理外部请求  
else if (外部请求空) → 处理内部请求
else → 处理混合请求
public void processQueue() {       
        while (true) {
            // 双队列为空判断
            if (queue.getInnerQueue().isEmpty() && queue.getOutQueue().isEmpty()) {
                state.setDirection(Direction.IDLE);
                return;
            }
            // 仅外部队列有数据
            if (queue.getInnerQueue().isEmpty()) {
                processSingleTarget(true, calculater());
                continue;
            }
            // 双队列都有数据
            if (queue.getOutQueue().isEmpty()) {
                processSingleTarget(false, queue.getInnerQueue().get(0));
                continue;
            }

            processIn_OutRequests();
        }
}

(4)SourceMontor的代码分析

image

image

复杂度与结构 数值
代码行数 357
语句数 215
类和接口数 7
方法调用语句数 113
每个类平均方法数 5.86
每个方法平均语句数 3.83
最复杂方法名 Operator.inputData()
最大复杂度 11
最大块深度 5
平均块深度 2.21
平均复杂度 2.17

     局部方法逻辑臃肿。部分方法复杂度高、块深度5层,存在过度嵌套和分支过多的问题。有的方法同时承担“格式校验、请求解析、队列添加”等多个职责,违背“单一职责原则”,维护和修改成本高。Main类职责过载承担了“输入读取、对象初始化、流程触发”等过多流程控制工作,主方法逻辑冗长。可读性差可读性与可维护性薄弱。注释覆盖率极低(仅1.4%),关键逻辑(如 processQueue() 的分支判断、solveCrossDirectionRequests()的方向决策),缺乏必要注释。

 

2.第二次作业

(1)题目:

对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客请求类、队列类以及控制类,具体设计可参考如下类图。
image
电梯运行规则与前阶段单类设计相同,但要处理如下情况:

  • 乘客请求楼层数有误,具体为高于最高楼层数或低于最低楼层数,处理方法:程序自动忽略此类输入,继续执行
  • 乘客请求不合理,具体为输入时出现连续的相同请求,例如<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

 

(2)类的设计

  由于第一次作业的代码,对类的划分相对合理,本次作业只需进行一部分的迭代优化。新增 LiftExecutor 类,专门封装电梯核心动作,负责 openDoor()/closeDoor()/moveOneFloor() 等动作执行,同步维护电梯运行状态实现请求决策(Operator)与动作执行(LiftExecutor)分离,符合单一职责原则。

代码实现类图:

image

 

(3)SourceMontor的代码分析

image

image

       相较于上一次代码,整体逻辑复杂度降低,多数方法的分支、嵌套得到简化。但是未解决分支过多、逻辑嵌套多问题。注释语句太少了,远远低于正常范围,代码的规范做的还是不到位,还需要继续改进。

3.第三次作业

(1)题目:

对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类,具体设计可参考如下类图。

image
电梯运行规则与前阶段相同,但有如下变动情况:

  • 乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
  • 对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)

注意:本次作业类设计必须符合如上要求(包含但不限于设计电梯类、乘客类、队列类以及控制类),凡是不符合类设计要求此题不得分,另外,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

(2)类的设计

       对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类。

实现代码的类图:

image

image

image

  相较于前两次代码,本次代码复杂度进一步降低,嵌套进一步降低达到了合理的数值,职责划分更加合理。

 

 三、踩坑心得

1.调度算法的理解有误

查看代码
测试用例: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: 7 Direction: DOWN
Current Floor: 6 Direction: DOWN
Open Door # Floor 6
Close Door

预期结果如下:
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

    运行结果在 7 楼→6 楼 之间多输出了一行 Current Floor: 7 Direction: DOWN,且缺少后续 6→5、5→4、4→3 的移动和停靠输出。这是由于代码判断内外部请求时会对队列里的楼层全部遍历一遍,选择距离当前楼层最近的楼层停靠,忽略了同方向优先级的要求。而正确的逻辑应该是处理请求时,扫描内外两个队列,如果此时请求队列有同方向的楼层,优先选择该楼层。若内外队列的都有同方向的楼层,则优先选择内部队列的楼层。注意队列的结构有队首和对尾,数据从队尾进,队首出。程序判断内外队列请求,选择下一个到达的楼层时只读取此时位于队首的数据,不能遍历队列中的所有数据,选择与当前楼层同方向且距当前楼层最近的楼层。一定要遵循同方向优先的规则和队列先进先出的特点。

2.代码运行超时

image

       有时代码运行超时的原因并不只是代码长度过长,还有可能是由于代码执行过程中运行的判断语句if-else过多(注意是代码运行时执行了的判断语句数量多,有时写的判断语句多,但是执行时执行的语句少就不会导致运行超时)、循环语句里的引用函数过多引起的。除此之外还有一点,输出楼层open、close door语句的方法,这里推荐使用楼层跳跃输出的策略,即先判断下一个楼层是哪一层,然后中间经过的楼层不用判断直接输出:Current Floor: 楼层数 Direction: 方向。如果使用每到一层都调用函数判断是不是目的楼层的策略,会大大增加运行时间开销,导致运行超时。

3.第三次作业代码去重需求

image

  刚开始按要求修改好代码提交只通过了两个知识点,后来经过检查后发现运行第二个样例结果是错误的。

查看代码
运行样例2:
1
20
<5,9>
<8>
<9,3>
<4>
<2>
end
运行结果为:
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: 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: 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
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
预期结果:
查看代码
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

       错误原因在于本次代码需要添加去重功能,即当输入相同请求时,会自动过滤去除。添加去重功能后,我通过了第二个测试点:

image

      对于第一个测试点,我用了很多样例测试,也进行了一些边界值测试,但是仍为发现问题,没有弄清楚该测试点的测试内容是什么。

四、改进建议

   1.优化调度算法,提升运行效率。替换仅处理首个请求为同向请求批量处理。

   2.补充有效性检验,避免无效请求。原代码未校验请求楼层的合法性(如超出电梯最小 / 最大楼层、与当前楼层相同),可能导致无限循环或无效移动;
 
   3.提高代码的可读性(注释过少,养成写注释的好习惯)和可维护性。

五、总结

      通过这次三次单部电梯调度问题的深入研究,我不仅提升了面向对象设计的能力,还在代码优化和问题解决方面积累了宝贵的经验。如培养类设计的全局思想。第一次作业进行类设计时尽量进行职责规划,提高代码的可扩展性,这样会大大减少后续作业的工程量,不用推翻前面的代码重写,导致自己手忙脚乱。编写代码前,我们需要正确理解核心算法的逻辑思想,从而更好编写出符合题目的代码内容。当发现错误时可以进行边界值测试,检测代码存在的逻辑漏洞,以及代码的健壮性。在之后的学习中,我会更加注重代码的质量和可维护性,努力写出更高效的代码,同时减少像if,while等循环嵌套代码的出现,优化自身的逻辑思路。

      

      

 

posted @ 2025-11-22 17:26  23207312  阅读(5)  评论(0)    收藏  举报