优化电梯调度4:基于最短路径算法

概述:

端午节过了,又开始学习了,基于juejin.cn/post/737729... 介绍最短寻求时间算法搭建电梯调度,本文将进一步分享基于最短路径算法实现一个电梯调度示例。

原理:

基于最短路径算法的方法在多层建筑中,电梯系统的效率对于用户体验至关重要。传统的电梯调度方法,如先来先服务(FCFS)和固定路由,往往无法在高峰时段提供最优服务。随着计算机科学的发展,我们可以利用图论中的最短路径算法来设计更高效的电梯调度系统。

电梯调度的挑战

电梯调度系统需要在满足多个请求的同时保持高效率。系统的挑战在于如何优化电梯的移动顺序,以减少等待时间和能源消耗。此外,调度系统还需考虑电梯的负载、优先级请求以及紧急情况。

最短路径算法的应用

最短路径算法,如Dijkstra或A*算法,通常用于寻找图中两点间的最短距离。在电梯调度中,我们可以将每个楼层视为图的一个节点,电梯在楼层之间的移动视为边。最短路径算法可以帮助我们找到一条路径,通过这条路径电梯可以以最小的成本(时间或距离)满足所有请求。

Java实现概述

在Java中实现电梯调度系统,我们可以创建一个Elevator类来模拟电梯的行为。该类包含方法来添加请求、移动电梯以及处理开关门动作。以下是关键组件的简要概述:

Elevator 类

Elevator类包含电梯的当前楼层、目标楼层列表、移动方向和状态(如门是否开启)。类中的方法允许添加请求、计算最短路径、移动到下一个目标楼层以及模拟开关门动作。

scss 复制代码
import java.util.PriorityQueue;
import java.util.Comparator;
/**
 * @Author derek_smart
 * @Date 2024/6/6 13:41
 * @Description 最短路径算法
 */
public class Elevator {
    //电梯当前所在的楼层
    private int currentFloor;
    // 用于存储向上的请求
    private PriorityQueue<Integer> upQueue;
    // 用于存储向下的请求
    private PriorityQueue<Integer> downQueue;
    //电梯当前的移动方向
    private Direction direction;
    //电梯门是否打开。
    private boolean doorsOpen;

    /**
     * 用于表示电梯的移动方向,包括向上 (`UP`)、向下 (`DOWN`) 和空闲 (`IDLE`)。
     */
    enum Direction {
        UP, DOWN, IDLE
    }

    public Elevator() {
        this.currentFloor = 5; // 假设电梯开始在底层
        this.direction = Direction.IDLE; // 初始状态为空闲
        this.doorsOpen = false;

        // 优先队列根据楼层排序,确保请求以适当的顺序处理
        this.upQueue = new PriorityQueue<>();
        this.downQueue = new PriorityQueue<>(Comparator.reverseOrder());
    }

    /**
     * 添加一个新的楼层请求。如果请求楼层高于当前楼层,将其加入上行队列;如果低于当前楼层,加入下行队列;如果电梯已在请求楼层,则直接打开门。
     * @param floor
     */
    public void addRequest(int floor) {
        if (floor == currentFloor) {
            // 如果电梯已经在请求的楼层,只需打开门即可
            openDoors();
        } else if (floor > currentFloor) {
            upQueue.add(floor);
            if (direction == Direction.IDLE) {
                direction = Direction.UP; // 设置电梯方向向上
            }
        } else {
            downQueue.add(floor);

            if (direction == Direction.IDLE) {
                direction = Direction.DOWN; // 设置电梯方向向下
            }
        }
    }

    /**
     * 处理所有待处理的楼层请求。根据当前方向,电梯会先服务上行或下行队列中的请求。当一个方向的请求处理完毕,电梯会改变方向或者变为空闲状态。
     */
    public void moveAndServe() {
        while (!upQueue.isEmpty() || !downQueue.isEmpty()) {
            if (direction == Direction.UP) {
                serveUpRequests();
            } else if (direction == Direction.DOWN) {
                serveDownRequests();
            }

            // 如果两个队列都为空,则电梯变为空闲状态
            if (upQueue.isEmpty() && downQueue.isEmpty()) {
                direction = Direction.IDLE;
            }
        }
    }

    /**
     * 服务所有上行请求,直到上行队列为空
     */
    private void serveUpRequests() {
        while (!upQueue.isEmpty()) {
            int nextFloor = upQueue.poll(); // 获取并移除下一个楼层请求
            moveToFloor(nextFloor);
        }
        // 向上的请求处理完毕,改变方向或变为空闲
        direction = downQueue.isEmpty() ? Direction.IDLE : Direction.DOWN;
    }

    /**
     * 服务所有下行请求,直到下行队列为空。
     */
    private void serveDownRequests() {
        while (!downQueue.isEmpty()) {
            int nextFloor = downQueue.poll(); // 获取并移除下一个楼层请求
            moveToFloor(nextFloor);
        }
        // 向下的请求处理完毕,改变方向或变为空闲
        direction = upQueue.isEmpty() ? Direction.IDLE : Direction.UP;
    }

    /**
     * 模拟电梯实际在楼层之间移动时的行为
     * @param targetFloor
     */
    private void moveToFloor(int targetFloor) {
        if (doorsOpen) {
            closeDoors(); // 如果门是开着的,先关闭
        }

        // 判断电梯移动的方向
        int moveDirection = (targetFloor > currentFloor) ? 1 : -1;

        // 逐层移动直到到达目标楼层
        while (currentFloor != targetFloor) {
            currentFloor += moveDirection;
            System.out.println("Elevator passing floor " + currentFloor);

            // 模拟在每一层的短暂停留,例如电梯减速或加速
            simulateIntermediateFloorDelay();
        }
        System.out.println("Elevator has arrived at floor " + currentFloor);
        openDoors(); // 到达后打开门
    }

    private void simulateIntermediateFloorDelay() {
        try {
            Thread.sleep(200); // 模拟电梯在每层楼停留的时间,比如200毫秒
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.println("Elevator movement interrupted between floors.");
        }
    }

    /**
     * 打开电梯门,并模拟门开的延迟
     */
    private void openDoors() {
        System.out.println("Opening doors at floor " + currentFloor);
        doorsOpen = true;
        // 模拟门开时间
        simulateDoorOperationDelay();
    }

    /**
     * 关闭电梯门,并模拟门关的延迟
     */
    private void closeDoors() {
        System.out.println("Closing doors at floor " + currentFloor);
        doorsOpen = false;
        // 模拟门关时间
        simulateDoorOperationDelay();
    }

    private void simulateMovementDelay() {
        try {
            Thread.sleep(1000); // 模拟电梯移动到下一层的时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 模拟电梯开门或关门的时间延迟
     */
    private void simulateDoorOperationDelay() {
        try {
            Thread.sleep(500); // 模拟电梯开门或关门的时间
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

当电梯接收到楼层请求时,根据请求楼层的位置,电梯将请求添加到相应的上行或下行队列中。电梯根据其当前方向来决定服务哪个队列的请求。如果当前方向是向上,电梯会继续服务上行队列中的请求,直到该队列为空。然后,如果下行队列不为空,电梯会改变方向并开始服务下行队列中的请求。同理,如果电梯向下移动,它会先服务下行队列中的请求,然后再看上行队列。

电梯在移动到每个请求楼层时,会模拟移动时间并在到达后打开门,之后再关闭门以继续服务其他请求

  1. 考虑电梯的移动方向来优化请求的处理顺序。
  2. 添加一个简单的模拟延迟来表示电梯在楼层之间移动的时间。
  3. 电梯在到达每个楼层时开门和关门的动作。

调度方法

调度方法利用最短路径算法来确定电梯应该如何移动以最有效地满足所有请求。这可能涉及到计算当前楼层到所有请求楼层的最短路径,并根据计算结果更新电梯的移动计划。

scss 复制代码
/**
 * 添加一个新的楼层请求。如果请求楼层高于当前楼层,将其加入上行队列;如果低于当前楼层,加入下行队列;如果电梯已在请求楼层,则直接打开门。
 * @param floor
 */
public void addRequest(int floor) {
    if (floor == currentFloor) {
        // 如果电梯已经在请求的楼层,只需打开门即可
        openDoors();
    } else if (floor > currentFloor) {
        upQueue.add(floor);
        if (direction == Direction.IDLE) {
            direction = Direction.UP; // 设置电梯方向向上
        }
    } else {
        downQueue.add(floor);

        if (direction == Direction.IDLE) {
            direction = Direction.DOWN; // 设置电梯方向向下
        }
    }
}

优化和实际应用

模拟测试当前楼层在5楼:

typescript 复制代码
/**
 * @Author derek_smart
 * @Date 2024/6/6 13:41
 * @Description 最短路径算法 -测试
 */
public class ElevatorSystem {
    public static void main(String[] args) {
        Elevator elevator = new Elevator();
        elevator.addRequest(5);
        elevator.addRequest(3);
        elevator.addRequest(0);
        elevator.addRequest(8);
        elevator.addRequest(2);
        elevator.moveAndServe();
    }
}
sequenceDiagram participant Main participant Elevator Main->>Elevator: new Elevator(5) // 假设电梯初始在5楼 activate Elevator Main->>Elevator: addRequest(5) Main->>Elevator: addRequest(3) Main->>Elevator: addRequest(0) Main->>Elevator: addRequest(8) Main->>Elevator: addRequest(2) Main->>Elevator: moveAndServe() Elevator->>Elevator: moveToFloor(5) // 电梯已在5楼,开门 Elevator->>Elevator: openDoors() Elevator->>Elevator: closeDoors() Elevator->>Elevator: moveToFloor(3) // 接着移动到3楼 Elevator->>Elevator: openDoors() Elevator->>Elevator: closeDoors() Elevator->>Elevator: moveToFloor(2) // 然后是2楼 Elevator->>Elevator: openDoors() Elevator->>Elevator: closeDoors() Elevator->>Elevator: moveToFloor(0) // 接着是底楼 Elevator->>Elevator: openDoors() Elevator->>Elevator: closeDoors() Elevator->>Elevator: moveToFloor(8) // 最后移动到8楼 Elevator->>Elevator: openDoors() Elevator->>Elevator: closeDoors() deactivate Elevator

为了使电梯调度更加适应实际情况,我们可以在算法中考虑电梯的最大载重、优先级请求(如VIP或紧急情况)以及电梯的能源消耗。此外,多电梯系统需要算法来协调不同电梯之间的动作,以避免不必要的重复服务和提高整体效率。

结论

基于最短路径算法的电梯调度方法提供了一种优化传统电梯系统的可能性。通过利用图论和计算机算法,我们可以设计出能够快速响应请求并降低等待时间的电梯调度系统。然而,实际应用中需要对算法进行细致的调整,以确保能够处理现实世界的复杂性和不可预见性。未来的电梯系统将更加智能化,能够自动适应乘客流量的变化,并提供更加舒适和高效的乘坐体验。

相关推荐
yaoxin5211237 小时前
269. Java Stream API - Map-Filter-Reduce算法模型
java·python·算法
招风的黑耳7 小时前
智慧养老项目:当SpringBoot遇到硬件,如何优雅地处理异常与状态管理?
java·spring boot·后端
回家路上绕了弯7 小时前
分布式锁原理深度解析:从理论到实践
分布式·后端
CC码码8 小时前
前端字符串排序搜索可以更加细化了
前端·javascript·面试
磊磊磊磊磊8 小时前
用AI做了个排版工具,分享一下如何高效省钱地用AI!
前端·后端·react.js
Crystal3288 小时前
冒泡排序 bubble sort
前端·javascript·面试
hgz07108 小时前
Spring Boot Starter机制
java·spring boot·后端
daxiang120922058 小时前
Spring boot服务启动报错 java.lang.StackOverflowError 原因分析
java·spring boot·后端
我家领养了个白胖胖8 小时前
极简集成大模型!Spring AI Alibaba ChatClient 快速上手指南
java·后端·ai编程
Learner__Q8 小时前
每天五分钟:动态规划-LeetCode高频题_day2
算法·leetcode·动态规划