第一次Blog-对PTA题目集5~7电梯调度分析

电梯调度作业总结

前言

这是第一次通过blog记录个人在学习Java过程中遇到的问题,主要记录了一个电梯模拟调度程序的迭代开发,在三次电梯迭代开发中,需求从基础功能逐步扩展至多类协作和复杂调度规则。核心需求变化如下:

题目1:实现电梯基础调度功能,处理内外请求,使用look算法,遵循方向优先原则。

题目2:引入单一职责原则(SRP),拆分电梯类职责,处理无效和重复请求。

题目3:请求格式改变,引入乘客类,外部请求处理后需将目的楼层加入内部队列。

本文将从题目分析、代码分析和心得体会三个方面,总结编写过程中的关键点。

第一次电梯调度代码分析

题目

设计一个电梯类,具体包含电梯的最大楼层数、最小楼层数(默认为1层)当前楼层、运行方向、运行状态,以及电梯内部乘客的请求队列和电梯外部楼层乘客的请求队列,其中,电梯外部请求队列需要区分上行和下行。
电梯运行规则如下:电梯默认停留在1层,状态为静止,当有乘客对电梯发起请求时(各楼层电梯外部乘客按下上行或者下行按钮或者电梯内部乘客按下想要到达的楼层数字按钮),电梯开始移动,当电梯向某个方向移动时,优先处理同方向的请求,当同方向的请求均被处理完毕然后再处理相反方向的请求。电梯运行过程中的状态包括停止、移动中、开门、关门等状态。当电梯停止时,如果有新的请求,就根据请求的方向或位置决定移动方向。电梯在运行到某一楼层时,检查当前是否有请求(访问电梯内请求队列和电梯外请求队列),然后据此决定移动方向。每次移动一个楼层,检查是否有需要停靠的请求,如果有,则开门,处理该楼层的请求,然后关门继续移动。
使用键盘模拟输入乘客的请求,此时要注意处理无效请求情况,例如无效楼层请求,比如超过大楼的最高或最低楼层。还需要考虑电梯的空闲状态,当没有请求时,电梯停留在当前楼层。
请编写一个Java程序,设计一个电梯类,包含状态管理、请求队列管理以及调度算法,并使用一些测试用例,模拟不同的请求顺序,观察电梯的行为是否符合预期,比如是否优先处理同方向的请求,是否在移动过程中处理顺路的请求等。为了降低编程难度,不考虑同时有多个乘客请求同时发生的情况,即采用串行处理乘客的请求方式(电梯只按照规则响应请求队列中当前的乘客请求,响应结束后再响应下一个请求),具体运行规则详见输入输出样例。

输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<乘客所在楼层数,乘梯方向>,其中,乘梯方向用UP代表上行,用DOWN代表下行(UP、DOWN必须大写)。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:

运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door

难点分析与解决办法

1.确定电梯的调度逻辑,采用的LOOK算法,遵循方向优先。
2.处理楼层时队列的使用,入队和出队的运用。
3.采用正则表达式对输入的数据进行拆解和存储。
4.运动过程中保证优先处理同向请求,并且只处理队头请求。

设计思路

类设计

1.枚举类Direction ,Status。
2.Elevator类,属性有minFloor,maxFloor,currentFloor(记录当前楼层),direction(记录电梯运行的方向),status(记录电梯运行状态),内部请求队列,外部请求队列。
3.外部请求队列,属性有楼层和方向。

主方法设计

1.main方法:负责基本的类调用,负责数据的输入与处理。

Elevator类方法设计

1.构造方法:public Elevator(int minFloor,int maxFloor)
2.添加内部请求:public void addInternalRequest(int floor)
3.添加外部请求:public LinkedList getInternalRequests()
4.调度算法设计:public void processRequests();
5.判断初始运动方向方法:private void determineDirection();
5.找到最进楼层(用于确定初始方向):private int findNearest();
6.电梯移动方法(用于输出电梯的状态):private void moveOneFloor();
7.处理当前楼层请求(判断是否要开门):private boolean processCurrentFloorRequests();
8.判断是否要改变方向(同方向处理完全后改变方向):private void checkDirectionChange();

附上我的源码和源码分析

1.类图:

2.源码:

点击查看代码
import java.util.*;

enum Direction {
    UP, DOWN, NULL
}

enum Status {
    STOP, MOVING
}

public class Main{
    public static class ExternalRequest{
        int floor;
        Direction direction;

        public ExternalRequest(int floor, Direction direction) {
            this.floor = floor;
            this.direction = direction;
        }
        public int getFloor(){
            return floor;
        }
        public Direction getDirection(){
            return direction;
        }
    }

    public static class Elevator {
        private final int minFloor;
        private final int maxFloor;
        private int currentFloor;//目前的楼层
        private Direction direction;//运动方向z`
        private Status status;//运动状态

        public Elevator(int minFloor,int maxFloor){//构造对象方法
            this.minFloor = minFloor;
            this.maxFloor = maxFloor;
            this.currentFloor = minFloor;
            this.status = Status.STOP;
            this.direction = Direction.NULL;
        }
        public int getMinFloor() {
            return minFloor;
        }
        public int getMaxFloor() {
            return maxFloor;
        }
        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 Status getStatus() {
            return status;
        }
        public void setStatus(Status status) {
            this.status = status;
        }
        public boolean isValid(int floor) {
            return floor >= minFloor && floor <= maxFloor;
        }
    }

    public static class RequestQueue{
        private LinkedList<ExternalRequest> externalRequests = new LinkedList<>();
        private LinkedList<Integer> internalRequests = new LinkedList<>();

        public RequestQueue(){
        }
        public void addExternalRequest(int floor,Direction direction){
            externalRequests.add(new ExternalRequest(floor, direction));
        }
        public void addInternalRequest(int floor){
            internalRequests.add(floor);
        }
        public LinkedList<ExternalRequest>getExternalRequests(){
            return externalRequests;
        }
        public LinkedList<Integer>getInternalRequests(){
            return internalRequests;
        }
        public void setExternalRequests(LinkedList<ExternalRequest>externalRequests){
            this.externalRequests = externalRequests;
        }

        public void setInternalRequests(LinkedList<Integer> internalRequests){
            this.internalRequests = internalRequests;
        }
    }
    public static class Controller{
        private Elevator elevator;
        private RequestQueue queue;

        public Controller(Elevator elevator,RequestQueue queue){
            this.elevator = elevator;
            this.queue = queue;
        }
        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;
        }

        private void determineDirection(){
            int nearestFloor=findNearest();
            if (nearestFloor==-1){
                elevator.direction=Direction.NULL;
                elevator.status=Status.STOP;
                return;
            }
            if(nearestFloor>elevator.currentFloor) {
                elevator.direction=Direction.UP;
            }
            else if(nearestFloor<elevator.currentFloor){
                elevator.direction=Direction.DOWN;
            }
        }
        private int findNearest(){
            int nearest=-1;
            int minDistance=100000;//初始化一个较大值;
            if(!queue.internalRequests.isEmpty()){
                int floor=queue.internalRequests.peek();
                int distance1=Math.abs(floor-elevator.currentFloor);//计算距离
                if(distance1<minDistance){//如果距离更小
                    minDistance=distance1;// 更新最小距离
                    nearest=floor;// 更新最近楼层
                }
            }
            if(!queue.externalRequests.isEmpty()){
                ExternalRequest efloor=queue.externalRequests.peek();
                int floor=efloor.floor;
                int distance2=Math.abs(floor-elevator.currentFloor);
                if(distance2<minDistance){
                    minDistance=distance2;
                    nearest=floor;
                }
            }return nearest;
        }
        private void moveOneFloor(){
            switch(elevator.direction){
                case UP:
                    elevator.currentFloor++;
                    break;
                case DOWN:
                    elevator.currentFloor--;
                    break;
                default:
                    return;
            }System.out.println("Current Floor: " + elevator.currentFloor + " Direction: " + elevator.direction);
        }
        private boolean processCurrentFloorRequests(){
            boolean hasRequest=false;
            if(!queue.internalRequests.isEmpty()&&queue.internalRequests.peek()==elevator.currentFloor){
                queue.internalRequests.poll();
                hasRequest=true;
            }
            if(!queue.externalRequests.isEmpty()){
                ExternalRequest head=queue.externalRequests.peek();
                if (head.floor==elevator.currentFloor&&head.direction==elevator.direction){
                    queue.externalRequests.poll();
                    hasRequest=true;
                }
            }
            return hasRequest;
        }
        private void checkDirectionChange(){
            if(queue.internalRequests.isEmpty()&&queue.externalRequests.isEmpty()){
                elevator.direction = Direction.NULL;
                elevator.status=Status.STOP;
                return;
            }
            if(elevator.direction==Direction.UP){
                boolean hasUp=false;
                if(!queue.internalRequests.isEmpty()&&queue.internalRequests.peek()>elevator.currentFloor){
                    hasUp=true;
                }
                if(!hasUp){
                    if(!hasUp&&!queue.externalRequests.isEmpty()){
                        ExternalRequest head = queue.externalRequests.peek();
                        if(head.floor > elevator.currentFloor){
                            hasUp=true;
                        }
                    }
                }
                if(!hasUp){
                    elevator.direction=Direction.DOWN;
                }
            }
            else if(elevator.direction==Direction.DOWN){
                boolean hasDown=false;
                if(!queue.internalRequests.isEmpty()&&queue.internalRequests.peek()<elevator.currentFloor){
                    hasDown=true;
                }
                if(!hasDown){
                    if(!hasDown&&!queue.externalRequests.isEmpty()){
                        ExternalRequest head=queue.externalRequests.peek();
                        if(head.floor<elevator.currentFloor){
                            hasDown=true;
                        }
                    }
                }
                if(!hasDown){
                    elevator.direction=Direction.UP;
                }
            }
        }
        public void processRequests(){//算法设计
            if(queue.internalRequests.isEmpty()&&queue.externalRequests.isEmpty()){
                elevator.status=Status.STOP;
                elevator.direction=Direction.NULL;
                return ;
            }
            while(!queue.internalRequests.isEmpty()||!queue.externalRequests.isEmpty()){
                if(elevator.status==Status.STOP&&elevator.direction==Direction.NULL) {
                    determineDirection();
                    elevator.status=Status.MOVING;
                    if(elevator.currentFloor==elevator.minFloor&&elevator.direction!=Direction.NULL){
                        System.out.println("Current Floor: " + elevator.currentFloor + " Direction: " + elevator.direction);
                    }
                }
                moveOneFloor();
                boolean hasRequest=processCurrentFloorRequests();
                if(hasRequest){
                    System.out.println("Open Door # Floor " + elevator.currentFloor);
                    System.out.println("Close Door");
                    elevator.status = Status.STOP;
                } else{
                    elevator.status = Status.MOVING;
                }
                Direction direction2=elevator.direction;
                checkDirectionChange();
                if(direction2!=elevator.direction){
                    boolean hasRequest1=processCurrentFloorRequests();
                    if(hasRequest1){
                        System.out.println("Open Door # Floor " + elevator.currentFloor);
                        System.out.println("Close Door");
                        elevator.status = Status.STOP;
                    } else{
                        elevator.status = Status.MOVING;
                    }
                }
            }
        }
    }
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        String data; //输入数据:字符串
        int floor = 0;
        int floor2 = -1000000;//判断是否重复输入
        Direction direction = null;
        Direction direction2 =  null;//判断重复方向
        int minFloor,maxFloor; //电梯最低楼层、最高楼层
        String request = ""; //提取出的乘客请求字符串
        ArrayList<String> list = new ArrayList<>(); //用于接收用户输入的数组
        data = input.next();
        while(!data.equalsIgnoreCase("End")){ //输入以“end”结束
            list.add(data);
            data = input.next();
        }

        minFloor = Integer.parseInt(list.get(0));//第一行,电梯最低楼层
        maxFloor = Integer.parseInt(list.get(1));//第二行,电梯最高楼层

        Elevator elevator = new Elevator(minFloor, maxFloor);//创建电梯对象
        RequestQueue queue = new RequestQueue();
        Controller controller = new Controller(elevator,queue);
        for(int i = 2; i < list.size(); i++){//从第三行开始为乘客请求
            request = list.get(i);
            if(request.contains(",")){//外部请求
                if (!request.matches("<\\d+,\\s*(UP|DOWN)>")) {
                    continue;
                }
                String[] parts = request.replaceAll("[<>]", "").split(",");
                floor = Integer.parseInt(parts[0].trim());
                direction = Direction.valueOf(parts[1].trim().toUpperCase());
                if(floor == floor2 && direction2 == direction){
                    continue;//如果两次相同则继续执行
                }
                floor2 = floor ;
                direction2 = direction;
                if(controller.elevator.isValid(floor)){
                    controller.queue.addExternalRequest(floor, direction);//外部请求入队,格式为<楼层数,方向>
                }
            }else{
                if (!request.matches("<\\d+>")) {//内部请求
                    continue;//忽略继续执行
                }
                floor = Integer.parseInt(request.replaceAll("[<>]", ""));
                if(floor == floor2){
                    continue;//如果两次相同则继续执行
                }
                floor2 = floor ;
                if(controller.elevator.isValid(floor)){
                    controller.queue.addInternalRequest(floor);//内部请求入队,格式为<楼层数>
                }
            }
        }
        controller.processRequests();//一次性处理所有的内、外部乘客请求
        input.close();
    }
}

源码分析

根据Source Monitor分析:
类和接口数量 5
每个类的方法数 2.40
平均每个方法的语句数 11.67
最大复杂度 19
最深块的行号 147
最大块深度 6
平均块深度 2.40
平均复杂度 5.33
最复杂的区域:findNearest().checkDirectionChange() 方法复杂度达 19,语句数 26,最大深度 6,逻辑复杂,易出错且难理解,应该拆解并简化逻辑。平均复杂度5.33偏高,应改进优化最复杂方法。降低复杂度。

设计历程的心得体会

这个电梯调度和我们日常生活是有点不一样的,刚拿到题目就盲目设计类与方法的话会很吃力,并且可能方向也是错误的,结合电梯运行的实例,仔细分析电梯运行逻辑和LOOK算法后,了解了电梯调度的底层逻辑之后,开始设计类和类方法。

踩坑心得

刚开始编写还是很顺利,题目给的测试用例也都能通过,但是提交却总是运行超时,因为老师给的测试用例不够,于是我开始自己设计测试用例,我也发现了其中的问题,就出现在改变方向这个方法上,简而言之就是,没有办法将处理完的请求移除队列(因为方向一直对不上,导致电梯上下反复跳转),这里的解决办法是多加了一条if语句,用于判断方向的改变,解决后,提交才正确。

第二次电梯调度代码分析

题目要求:

对之前电梯调度程序进行迭代性设计,目的为解决电梯类职责过多的问题,类设计要求遵循单一职责原则(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.类图:

2.源码:

点击查看代码
import java.util.*;

enum Direction {
    UP, DOWN, NULL
}

enum Status {
    STOP, MOVING
}

public class Main{
    public static class ExternalRequest{
        int floor;
        Direction direction;

        public ExternalRequest(int floor, Direction direction) {
            this.floor = floor;
            this.direction = direction;
        }
        public int getFloor(){
            return floor;
        }
        public Direction getDirection(){
            return direction;
        }
    }

    public static class Elevator {
        private final int minFloor;
        private final int maxFloor;
        private int currentFloor;//目前的楼层
        private Direction direction;//运动方向z`
        private Status status;//运动状态

        public Elevator(int minFloor,int maxFloor){//构造对象方法
            this.minFloor = minFloor;
            this.maxFloor = maxFloor;
            this.currentFloor = minFloor;
            this.status = Status.STOP;
            this.direction = Direction.NULL;
        }
        public int getMinFloor() {
            return minFloor;
        }
        public int getMaxFloor() {
            return maxFloor;
        }
        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 Status getStatus() {
            return status;
        }
        public void setStatus(Status status) {
            this.status = status;
        }
        public boolean isValid(int floor) {
            return floor >= minFloor && floor <= maxFloor;
        }
    }

    public static class RequestQueue{
        private LinkedList<ExternalRequest> externalRequests = new LinkedList<>();
        private LinkedList<Integer> internalRequests = new LinkedList<>();

        public RequestQueue(){
        }
        public void addExternalRequest(int floor,Direction direction){
            externalRequests.add(new ExternalRequest(floor, direction));
        }
        public void addInternalRequest(int floor){
            internalRequests.add(floor);
        }
        public LinkedList<ExternalRequest>getExternalRequests(){
            return externalRequests;
        }
        public LinkedList<Integer>getInternalRequests(){
            return internalRequests;
        }
        public void setExternalRequests(LinkedList<ExternalRequest>externalRequests){
            this.externalRequests = externalRequests;
        }

        public void setInternalRequests(LinkedList<Integer> internalRequests){
            this.internalRequests = internalRequests;
        }
    }
    public static class Controller{
        private Elevator elevator;
        private RequestQueue queue;

        public Controller(Elevator elevator,RequestQueue queue){
            this.elevator = elevator;
            this.queue = queue;
        }
        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;
        }

        private void determineDirection(){
            int nearestFloor=findNearest();
            if (nearestFloor==-1){
                elevator.direction=Direction.NULL;
                elevator.status=Status.STOP;
                return;
            }
            if(nearestFloor>elevator.currentFloor) {
                elevator.direction=Direction.UP;
            }
            else if(nearestFloor<elevator.currentFloor){
                elevator.direction=Direction.DOWN;
            }
        }
        private int findNearest(){
            int nearest=-1;
            int minDistance=100000;//初始化一个较大值;
            if(!queue.internalRequests.isEmpty()){
                int floor=queue.internalRequests.peek();
                int distance1=Math.abs(floor-elevator.currentFloor);//计算距离
                if(distance1<minDistance){//如果距离更小
                    minDistance=distance1;// 更新最小距离
                    nearest=floor;// 更新最近楼层
                }
            }
            if(!queue.externalRequests.isEmpty()){
                ExternalRequest efloor=queue.externalRequests.peek();
                int floor=efloor.floor;
                int distance2=Math.abs(floor-elevator.currentFloor);
                if(distance2<minDistance){
                    minDistance=distance2;
                    nearest=floor;
                }
            }return nearest;
        }
        private void moveOneFloor(){
            switch(elevator.direction){
                case UP:
                    elevator.currentFloor++;
                    break;
                case DOWN:
                    elevator.currentFloor--;
                    break;
                default:
                    return;
            }System.out.println("Current Floor: " + elevator.currentFloor + " Direction: " + elevator.direction);
        }
        private boolean processCurrentFloorRequests(){
            boolean hasRequest=false;
            if(!queue.internalRequests.isEmpty()&&queue.internalRequests.peek()==elevator.currentFloor){
                queue.internalRequests.poll();
                hasRequest=true;
            }
            if(!queue.externalRequests.isEmpty()){
                ExternalRequest head=queue.externalRequests.peek();
                if (head.floor==elevator.currentFloor&&head.direction==elevator.direction){
                    queue.externalRequests.poll();
                    hasRequest=true;
                }
            }
            return hasRequest;
        }
        private void checkDirectionChange(){
            if(queue.internalRequests.isEmpty()&&queue.externalRequests.isEmpty()){
                elevator.direction = Direction.NULL;
                elevator.status=Status.STOP;
                return;
            }
            if(elevator.direction==Direction.UP){
                boolean hasUp=false;
                if(!queue.internalRequests.isEmpty()&&queue.internalRequests.peek()>elevator.currentFloor){
                    hasUp=true;
                }
                if(!hasUp){
                    if(!hasUp&&!queue.externalRequests.isEmpty()){
                        ExternalRequest head = queue.externalRequests.peek();
                        if(head.floor > elevator.currentFloor){
                            hasUp=true;
                        }
                    }
                }
                if(!hasUp){
                    elevator.direction=Direction.DOWN;
                }
            }
            else if(elevator.direction==Direction.DOWN){
                boolean hasDown=false;
                if(!queue.internalRequests.isEmpty()&&queue.internalRequests.peek()<elevator.currentFloor){
                    hasDown=true;
                }
                if(!hasDown){
                    if(!hasDown&&!queue.externalRequests.isEmpty()){
                        ExternalRequest head=queue.externalRequests.peek();
                        if(head.floor<elevator.currentFloor){
                            hasDown=true;
                        }
                    }
                }
                if(!hasDown){
                    elevator.direction=Direction.UP;
                }
            }
        }
        public void processRequests(){//算法设计
            if(queue.internalRequests.isEmpty()&&queue.externalRequests.isEmpty()){
                elevator.status=Status.STOP;
                elevator.direction=Direction.NULL;
                return ;
            }
            while(!queue.internalRequests.isEmpty()||!queue.externalRequests.isEmpty()){
                if(elevator.status==Status.STOP&&elevator.direction==Direction.NULL) {
                    determineDirection();
                    elevator.status=Status.MOVING;
                    if(elevator.currentFloor==elevator.minFloor&&elevator.direction!=Direction.NULL){
                        System.out.println("Current Floor: " + elevator.currentFloor + " Direction: " + elevator.direction);
                    }
                }
                moveOneFloor();
                boolean hasRequest=processCurrentFloorRequests();
                if(hasRequest){
                    System.out.println("Open Door # Floor " + elevator.currentFloor);
                    System.out.println("Close Door");
                    elevator.status = Status.STOP;
                } else{
                    elevator.status = Status.MOVING;
                }
                Direction direction2=elevator.direction;
                checkDirectionChange();
                if(direction2!=elevator.direction){
                    boolean hasRequest1=processCurrentFloorRequests();
                    if(hasRequest1){
                        System.out.println("Open Door # Floor " + elevator.currentFloor);
                        System.out.println("Close Door");
                        elevator.status = Status.STOP;
                    } else{
                        elevator.status = Status.MOVING;
                    }
                }
            }
        }
    }
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        String data; //输入数据:字符串
        int floor = 0;
        int floor2 = -1000000;//判断是否重复输入
        Direction direction = null;
        Direction direction2 =  null;//判断重复方向
        int minFloor,maxFloor; //电梯最低楼层、最高楼层
        String request = ""; //提取出的乘客请求字符串
        ArrayList<String> list = new ArrayList<>(); //用于接收用户输入的数组
        data = input.next();
        while(!data.equalsIgnoreCase("End")){ //输入以“end”结束
            list.add(data);
            data = input.next();
        }

        minFloor = Integer.parseInt(list.get(0));//第一行,电梯最低楼层
        maxFloor = Integer.parseInt(list.get(1));//第二行,电梯最高楼层

        Elevator elevator = new Elevator(minFloor, maxFloor);//创建电梯对象
        RequestQueue queue = new RequestQueue();
        Controller controller = new Controller(elevator,queue);
        for(int i = 2; i < list.size(); i++){//从第三行开始为乘客请求
            request = list.get(i);
            if(request.contains(",")){//外部请求
                if (!request.matches("<\\d+,\\s*(UP|DOWN)>")) {
                    continue;
                }
                String[] parts = request.replaceAll("[<>]", "").split(",");
                floor = Integer.parseInt(parts[0].trim());
                direction = Direction.valueOf(parts[1].trim().toUpperCase());
                if(floor == floor2 && direction2 == direction){
                    continue;//如果两次相同则继续执行
                }
                floor2 = floor ;
                direction2 = direction;
                if(controller.elevator.isValid(floor)){
                    controller.queue.addExternalRequest(floor, direction);//外部请求入队,格式为<楼层数,方向>
                }
            }else{
                if (!request.matches("<\\d+>")) {//内部请求
                    continue;//忽略继续执行
                }
                floor = Integer.parseInt(request.replaceAll("[<>]", ""));
                if(floor == floor2){
                    continue;//如果两次相同则继续执行
                }
                floor2 = floor ;
                if(controller.elevator.isValid(floor)){
                    controller.queue.addInternalRequest(floor);//内部请求入队,格式为<楼层数>
                }
            }
        }
        controller.processRequests();//一次性处理所有的内、外部乘客请求
        input.close();
    }
}

代码分析

行数 315,
语句 208,
分支语句百分比 23.6,
方法调用语句 51,
类和接口数量 7,
每个类的方法数 4.29,
最大复杂度:44
最深块的行号:190
最大块深度:8
平均块深度:4.00
平均复杂度:3.97
平均每个方法的语句:5.40

心得体会

一开始做这个题目,根据题目给出的类图,一步一步把类设计出来,然后把电梯里面的方法分离出来。在分离职责的过程中,并未遇到难以解决的地方。单一职责原则(SRP) 的实践让我深刻认识到类的设计。通过将请求存储交给 RequestQueue、调度逻辑交给 Controller,代码结构更清晰。
收获:虽然拆分后类的数量增加,但调试变得更容易。例如,修改调度算法时只需关注 Controller,而无需担心影响请求存储逻辑。

第三次电梯调度代码分析

题目要求

对之前电梯调度程序再次进行迭代性设计,加入乘客类(Passenger),取消乘客请求类,类设计要求遵循单一职责原则(SRP),要求必须包含但不限于设计电梯类、乘客类、队列类以及控制类。
电梯运行规则与前阶段相同,但有如下变动情况:

乘客请求输入变动情况:外部请求由之前的<请求楼层数,请求方向>修改为<请求源楼层,请求目的楼层>
对于外部请求,当电梯处理该请求之后(该请求出队),要将<请求源楼层,请求目的楼层>中的请求目的楼层加入到请求内部队列(加到队尾)
注意:本次作业类设计必须符合如上要求(包含但不限于设计电梯类、乘客类、队列类以及控制类),凡是不符合类设计要求此题不得分,另外,PTA得分代码界定为第一次提交的最高分代码(因此千万不要把第一次及第二次电梯程序提交到本次题目中测试)。

输入格式:
第一行输入最小电梯楼层数。
第二行输入最大电梯楼层数。
从第三行开始每行输入代表一个乘客请求。

电梯内乘客请求格式:<楼层数>
电梯外乘客请求格式:<请求源楼层,请求目的楼层>,其中,请求源楼层表示乘客发起请求所在的楼层,请求目的楼层表示乘客想要到达的楼层。
当输入“end”时代表输入结束(end不区分大小写)。
输出格式:
模拟电梯的运行过程,输出方式如下:

运行到某一楼层(不需要停留开门),输出一行文本:
Current Floor: 楼层数 Direction: 方向
运行到某一楼层(需要停留开门)输出两行文本:
Open Door # Floor 楼层数
Close Door

题目分析

1.相比与前两次,输入方式进行了改变,外部请求从输入当前楼层和方向改变为输入当前楼层和目标楼层,但只要通过其的输入来得到外部请求的方向,则与前两次的算法相同,需要改变外部请求类,将Direction改成DestinationFloor;
2.添加乘客类,初始楼层和目标楼层更符合实际情况。
3.增加了执行外部请求时将其目标楼层放在内部请求末尾,添加一个语句,每次处理完后,将请求添加到内部请求队尾。

附上我的源码和源码分析

1.类图

2.源码

点击查看代码
import java.util.*;

enum Direction {
    UP, DOWN, NULL
}

enum Status {
    STOP, MOVING
}
public class Main{
    public static void main(String[] args){
        Scanner input = new Scanner(System.in);
        String data; //输入数据:字符串
        int floor = 0;
        int destinationFloor = 0;
        int destinationFloor2 = -1000000;
        int floor2 = -1000000;//判断是否重复输入
        int floor3 = -1000000;
        int minFloor,maxFloor; //电梯最低楼层、最高楼层
        String request = ""; //提取出的乘客请求字符串
        ArrayList<String> list = new ArrayList<>(); //用于接收用户输入的数组
        data = input.next();
        while(!data.equalsIgnoreCase("End")){ //输入以“end”结束
            list.add(data);
            data = input.next();
        }
        minFloor = Integer.parseInt(list.get(0));//第一行,电梯最低楼层
        maxFloor = Integer.parseInt(list.get(1));//第二行,电梯最高楼层
        Elevator elevator = new Elevator(minFloor, maxFloor);//创建电梯对象
        RequestQueue queue = new RequestQueue();
        Controller controller = new Controller(elevator,queue);
        for(int i = 2; i < list.size(); i++){//从第三行开始为乘客请求
            request = list.get(i);
            if(request.contains(",")){//外部请求
                if (!request.matches("<\\d+,\\s*\\d+>")) {
                    continue;
                }
                String[] parts = request.replaceAll("[<>]", "").split(",");
                floor = Integer.parseInt(parts[0].trim());
                destinationFloor = Integer.parseInt(parts[1].trim());
                if(floor == floor2 && destinationFloor == destinationFloor2){
                    continue;//如果两次相同则继续执行
                }
                floor2 = floor ;
                destinationFloor2 = destinationFloor;
                if(controller.getElevator().isValid(floor)&&controller.getElevator().isValid(destinationFloor)){
                    controller.getQueue().addExternalRequest(floor, destinationFloor);//外部请求入队,格式为<楼层数,方向>
                }
            }else{
                if (!request.matches("<\\d+>")) {//内部请求
                    continue;//忽略继续执行
                }
                floor = Integer.parseInt(request.replaceAll("[<>]", ""));
                if(floor == floor3){
                    continue;//如果两次相同则继续执行
                }
                floor3 = floor ;
                if(controller.getElevator().isValid(floor)){
                    controller.getQueue().addInternalRequest(floor);//内部请求入队,格式为<楼层数>
                }
            }
        }
        controller.processRequests();//一次性处理所有的内、外部乘客请求
        input.close();
    }
}
class Elevator {
    private final int minFloor;
    private final int maxFloor;
    private int currentFloor;//目前的楼层
    private Direction direction;//运动方向z`
    private Status status;//运动状态

    public Elevator(int minFloor,int maxFloor){//构造对象方法
        this.minFloor = minFloor;
        this.maxFloor = maxFloor;
        this.currentFloor = minFloor;
        this.status = Status.STOP;
        this.direction = Direction.NULL;
    }
    public int getMinFloor() {
        return minFloor;
    }
    public int getMaxFloor() {
        return maxFloor;
    }
    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 Status getStatus() {
        return status;
    }
    public void setStatus(Status status) {
        this.status = status;
    }
    public boolean isValid(int floor) {
        return floor >= minFloor && floor <= maxFloor;
    }
}
class RequestQueue{
    private LinkedList<Passenger> externalRequests = new LinkedList<>();
    private LinkedList<Integer> internalRequests = new LinkedList<>();

        public RequestQueue(){
    }
    public void addExternalRequest(int floor,int destinationFloor){
        externalRequests.add(new Passenger(floor, destinationFloor));
    }
    public void addInternalRequest(int floor){
        internalRequests.add(floor);
    }
    public LinkedList<Passenger>getExternalRequests(){
        return externalRequests;
    }
    public LinkedList<Integer>getInternalRequests(){
        return internalRequests;
    }
    public void setExternalRequests(LinkedList<Passenger>externalRequests){
        this.externalRequests = externalRequests;
    }

    public void setInternalRequests(LinkedList<Integer> internalRequests){
        this.internalRequests = internalRequests;
    }
}
class Controller{
    private Elevator elevator;
    private RequestQueue queue;

    public Controller(Elevator elevator,RequestQueue queue){
        this.elevator = elevator;
        this.queue = queue;
    }
    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;
    }

    private void determineDirection(){
        int nearestFloor=findNearest();
        if (nearestFloor==-1){
            elevator.setDirection(Direction.NULL);
            elevator.setStatus(Status.STOP);
            return;
        }
        if(nearestFloor>elevator.getCurrentFloor()) {
            elevator.setDirection(Direction.UP);
        }
        else if(nearestFloor<elevator.getCurrentFloor()){
            elevator.setDirection(Direction.DOWN);
        }
    }
    private int findNearest(){
        int nearest=-1;
        int minDistance=100000;//初始化一个较大值;
        if(!queue.getInternalRequests().isEmpty()){
            int floor=queue.getInternalRequests().peek();
            int distance1=Math.abs(floor-elevator.getCurrentFloor());//计算距离
            if(distance1<minDistance){//如果距离更小
                minDistance=distance1;// 更新最小距离
                nearest=floor;// 更新最近楼层
            }
        }
        if(!queue.getExternalRequests().isEmpty()){
            Passenger efloor=queue.getExternalRequests().peek();
            int floor=efloor.getSourceFloor();
            int distance2=Math.abs(floor-elevator.getCurrentFloor());
            if(distance2<minDistance){
                minDistance=distance2;
                nearest=floor;
            }
        }return nearest;
    }
    private void moveOneFloor(){
        switch(elevator.getDirection()){
            case UP:
                int Floor = elevator.getCurrentFloor()+1;
                elevator.setCurrentFloor(Floor);
                break;
            case DOWN:
                int Floor1 = elevator.getCurrentFloor()-1;
                elevator.setCurrentFloor(Floor1);
                break;
            default:
                return;
        }System.out.println("Current Floor: " + elevator.getCurrentFloor() + " Direction: " + elevator.getDirection());
    }
    private boolean processCurrentFloorRequests(){
        boolean hasRequest=false;
        if(!queue.getInternalRequests().isEmpty()&&queue.getInternalRequests().peek()==elevator.getCurrentFloor()){
            queue.getInternalRequests().poll();
            hasRequest=true;
        }
        if(!queue.getExternalRequests().isEmpty()){
            Passenger head=queue.getExternalRequests().peek();
            if (head.getSourceFloor()==elevator.getCurrentFloor()&&head.getDirection()==elevator.getDirection()){
                queue.getExternalRequests().poll();
                queue.getInternalRequests().add(head.getDestinationFloor());
                hasRequest=true;
            }
        }
        return hasRequest;
    }
    private void checkDirectionChange(){
        if(queue.getInternalRequests().isEmpty()&&queue.getExternalRequests().isEmpty()){
            elevator.setDirection(Direction.NULL);
            elevator.setStatus(Status.STOP);
            return;
        }
        if(elevator.getDirection()==Direction.UP){
            boolean hasUp=false;
            if(!queue.getInternalRequests().isEmpty()&&queue.getInternalRequests().peek()>elevator.getCurrentFloor()){
                hasUp=true;
            }
            if(!hasUp){
                if(!hasUp&&!queue.getExternalRequests().isEmpty()){
                    Passenger head = queue.getExternalRequests().peek();
                    if(head.getSourceFloor() > elevator.getCurrentFloor()){
                        hasUp=true;
                    }
                }
            }
            if(!hasUp){
                elevator.setDirection(Direction.DOWN);
            }
        }
        else if(elevator.getDirection()==Direction.DOWN){
            boolean hasDown=false;
            if(!queue.getInternalRequests().isEmpty()&&queue.getInternalRequests().peek()<elevator.getCurrentFloor()){
                hasDown=true;
            }
            if(!hasDown){
                if(!hasDown&&!queue.getExternalRequests().isEmpty()){
                    Passenger head=queue.getExternalRequests().peek();
                    if(head.getSourceFloor()<elevator.getCurrentFloor()){
                        hasDown=true;
                    }
                }
            }
            if(!hasDown){
                elevator.setDirection(Direction.UP);
            }
        }
    }
    public void processRequests(){//算法设计
        if(queue.getInternalRequests().isEmpty()&&queue.getExternalRequests().isEmpty()){
            elevator.setStatus(Status.STOP);
            elevator.setDirection(Direction.NULL);
            return ;
        }
        while(!queue.getInternalRequests().isEmpty()||!queue.getExternalRequests().isEmpty()){
            if(elevator.getStatus()==Status.STOP&&elevator.getDirection()==Direction.NULL) {
                determineDirection();
                elevator.setStatus(Status.MOVING);
                if(elevator.getCurrentFloor()==elevator.getMinFloor()&&elevator.getDirection()!=Direction.NULL){
                    System.out.println("Current Floor: " + elevator.getCurrentFloor() + " Direction: " + elevator.getDirection());
                }
            }
            moveOneFloor();
            boolean hasRequest=processCurrentFloorRequests();
            if(hasRequest){
                System.out.println("Open Door # Floor " + elevator.getCurrentFloor());
                System.out.println("Close Door");
                elevator.setStatus(Status.STOP);
            } else{
                elevator.setStatus(Status.MOVING);
            }
            Direction direction2=elevator.getDirection();
            checkDirectionChange();
            if(direction2!=elevator.getDirection()){
                boolean hasRequest1=processCurrentFloorRequests();
                if(hasRequest1){
                    System.out.println("Open Door # Floor " + elevator.getCurrentFloor());
                    System.out.println("Close Door");
                    elevator.setStatus(Status.STOP);
                } else{
                    elevator.setStatus(Status.MOVING);
                }
            }
        }
    }
}
class Passenger{
    private Integer sourceFloor = null;
    private Integer destinationFloor = null;

    public Passenger() {
    }
    public Passenger(Integer sourceFloor,Integer destinationFloor){
        this.sourceFloor = sourceFloor;
        this.destinationFloor = destinationFloor;
    }
    public Passenger(Integer destinationFloor){
        this.destinationFloor = destinationFloor;
    }
    public Integer getSourceFloor(){
        return sourceFloor;
    }
    public void setSourceFloor(Integer sourceFloor){
        this.sourceFloor = sourceFloor;
    }
    public Integer getDestinationFloor(){
        return destinationFloor;
    }
    public void setDestinationFloor(Integer destinationFloor){
        this.destinationFloor = destinationFloor;
    }
    public Direction getDirection(){
        if (sourceFloor < destinationFloor){
            return Direction.UP;
        } else if (sourceFloor > destinationFloor){
            return Direction.DOWN;
        } else {
            return Direction.NULL;
        }
    }
}

代码分析

行数 334,
语句 225,
分支语句百分比 23.1,
方法调用语句 51,
类和接口数量 7,
每个类的方法数 5.00,
最大复杂度:44
最深块的行号:222
最大块深度:8
平均块深度:4.74
平均复杂度:3.62
平均每个方法的语句:6.29

心得体会

1.通过简化不必要的判断,使得平均复杂度降低。

踩坑心得

1.不要一来就直接写代码,一定要先理解需求,并且做好设计,一定要做好设计,不然很容易写错方向。
2.算法要尽可能的简单高效,这样可以避免很多不必要的麻烦,并且可以提高效率。
3.要学会自己设计测试用例以及代码的调试,不然很难发现比较隐秘的错误,陷入循环时调试尤其重要。
4.编程是团队合作,切忌单打独斗,可以多多交流自己的观点和算法,再和其他人的进行比较。

5.从这个提交列表就能看出自己学会调试是非常重要的。

总结

这一次的大作业让我收获了很多。
1.在代码迭代过程中,我对 Java 有了更为深刻的认识,深刻体会到 Java 与 C 语言的显著差异,明白不能再沿用学习 C 语言的思维模式来学习 Java。C语言是面向过程,而Java是面向对象,这个差别尤为重要。
2.此次作业让我收获颇丰:掌握了正则表达式、队列的运用,还对类的设计及类与类之间关系的处理有了更深入的理解。从最初只设计一个Elevator类实现全部功能,到设计多个类,实现单一职则,将一个个的功能分割出去,使得代码复杂度降低的同时,可读性也提高了不少,每个类都只实现一小部分功能,修改的话只需要改一小部分,使代码可以进行更好的维护和扩展。
3.能够有意识地遵循单一职责原则、迪米特法则,同时也深刻意识到正确全面设置测试用例以及熟练运用单步调试的关键作用。

改进建议

然而,在实践过程中,我也清晰地发现了自身的不足。在处理方法间关系方面不够灵活,降低代码复杂度上需持续努力,尤其是在设计算法时,要非常仔细的理解题目的需求,明确运行的底层逻辑。此外,对于实际问题的抽象能力有很大的提升空间,实际解决问题的能力较为薄弱,对 Java 自带方法的掌握不够深入,很大方法都是后期使用时学会的,这些都降低了编写效率。后续我会着重加强对 Java 内置方法的学习,以提升解题速度与质量。
对于自己,我也有一些改进建议:线上课程讲解能更好的做好笔记,仔细理解老师的逻辑,在听完线上课后,要定期复习,要通过实际编码来提高自己的编程能力,不能仅仅是听课,在线下课程更加要认真仔细,跟上老师的思路节奏,记好笔记,以便课后的实践。课后的实践能力尤其重要,要通过做项目来真实的提高自己的能力,而不能停留在表面的学习上。

posted @ 2025-04-20 22:52  翻斗花园突击手胡图图  阅读(28)  评论(0)    收藏  举报