数据结构与算法设计——模拟电梯运行

文章描述了一个电梯运行的模拟系统,包括乘客类、电梯类和大楼类的实现,模拟了一部电梯的运行过程。讨论了电梯的调度策略,如直上直下,并提出了可能的优化方向,如增加电梯数量和优化乘客生成方式。同时指出了输出界面的静态性,建议改进为动态展示。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题

模拟电梯的运行. 以下为基本假设和调度策略,可以根据需要添加其他假设或对现有策略进行修改:

电梯最初从一楼开始运行
如果没有呼叫,则停在原地
乘客先下后上,如果满员,不能超载
如果电梯已经满员,且中间层无乘客出电梯,则直达目的层
请分别模拟只有一部电梯和有两部电梯(联动)的系统,并讨论如何优化其调度策略.在这里插入图片描述

假设和约定

  1. 乘客自觉 乘客呼叫电梯的行为是自身意愿的准确反映:乘客在电梯外的某一楼层呼叫时,要上楼的话,那么他会按上楼键而不是下楼键。
  2. 乘客出入电梯理想 电梯移动过程中可能停靠在某一楼层,乘客出入电梯不需要损耗时间。因此电梯移动过程的时间开销只与电梯路径有关,与是否停靠、停靠时出入乘客的流量无关。
  3. 电梯状态理想 电梯只有停止状态和移动状态,移动时电梯匀速运动,而不是像现实中要加速、均速、减速来回变换。

实现代码

抽象

乘客类 cpassenger

成员含义
from_floor所在楼层
to_floor要去楼层
isin状态:是否在特定组
id编号

电梯类 Elevator

成员含义
nowFloor电梯当前所在楼层
pin[maxEleNum]电梯里的乘客列表
run_status电梯运行状态
clockBegin开始运行时刻
clockExpectAim最近停靠的时刻
inButton电梯内楼层按钮
exButton电梯外楼层按钮

大楼类(模拟过程)SimBuilding

成员含义
e1电梯1(这块写死了,有空再回头改吧
pwaitting大楼中正在等电梯的乘客
phav大楼中已经坐过电梯的乘客
timeRunaFloor电梯运行时经过一层楼所需时间
simulationLength模拟时长

Simulation.h

#define maxEleNum 10
#define BudfloorNum 9

enum isInElevator{in,out};
class cpassenger
{
public:
    int from_floor;//所在楼层
    int to_floor;//要去楼层
    isInElevator isin;//是否在特定组中,1在,0不在
    char id;//编号
    cpassenger();
    cpassenger(int from, int to);
};

enum runStatus{up, down, stop};
enum floorStatus{aim, pass};

class Elevator
{
public:
    int nowFloor;//电梯当前所在楼层
    cpassenger pin[maxEleNum];
    runStatus run_status;//电梯运行状态
    int clockBegin;
    int clockExpectAim;
    floorStatus inButton[BudfloorNum+1];//楼层按钮,1按下,0未按(目的楼层)
    floorStatus exButton[BudfloorNum+1];//消息队列,(外面等待人所在的楼层)

    Elevator();//构造函数,默认9层
    int CurCount();
};

class SimBuilding
{
private:
    Elevator e1;
    cpassenger pwaitting[100]; ///正在等电梯的乘客
    cpassenger phav[100];      ///坐过电梯的乘客(人次)

    int timeRunaFloor;
    int simulationLength;

    RandomNumber rnd;            // use for arrival and service times

public:
    SimBuilding(int mf=9);
    bool Havpag(int fl, int fh); //某层楼是否有乘客
    int WaitCount();//整栋楼等电梯的乘客数(用于遍历乘客)
    int HavCount();//坐过电梯的乘客数(用于总结)
    void Call(int clock, cpassenger wp);
    void UpdateAim(int clock);
    int Enter(int clock);
    int Depart(int clock);
    void Sort();

    void Move(int clock);

    void RunSimulation(void);           // execute study
    void PrintCurStats();  // print stats

    void PrintSimulationResults(void);  // print stats
};

Simulation.cpp


cpassenger::cpassenger() {
    from_floor = 1;
    to_floor = BudfloorNum;
    isin = in;
    id = '?';
}

cpassenger::cpassenger(int from, int to) {
    from_floor = from;
    to_floor = to;
    isin = in;
    id = '?';
}

Elevator::Elevator()
{
    run_status=stop;//初始停止
    nowFloor=1;//电梯初始状态在第一层
    for(int i=1; i<=BudfloorNum; i++)//消息数组的初始化
    {
        inButton[i]=pass;
        exButton[i]=pass;
    }
    for (int j = 0; j < maxEleNum; j++)
        pin[j].isin = out;
}

int Elevator::CurCount() {
    int curCount=0;
    for (int j = 0; j < maxEleNum; j++)
        if (pin[j].isin == in)
            curCount++;
    return curCount;
}

SimBuilding::SimBuilding(int mf) {
    Elevator e1=Elevator();
    for (int j = 0; j < 100; j++)
        pwaitting[j].isin = out;  //没有等电梯的人

    for (int j = 0; j < 100; j++)
        phav[j].isin = out;        //没有坐过电梯的人

//    cout << "shuru runTimepFloor";
//    cin >> timeRunaFloor;
    timeRunaFloor = 3;

//    cout << "shuru simulationLength";
//    cin >> simulationLength;
    simulationLength =1000;
}

void SimBuilding::RunSimulation(void) {
    cpassenger newPassenger;
    int clock = 0;
    while (clock < simulationLength){
        Move(clock);
        if (clock == 0 || clock == 25 || clock == 4 || clock == 7 || clock == 40) { // || clock == 4
            newPassenger =cpassenger(); ///之后随机楼层
            if (clock == 4) newPassenger=cpassenger(4,2);
            if (clock == 7) newPassenger=cpassenger(3,6);
            if (clock == 40) newPassenger=cpassenger(9,7);
            cout << endl;
            PrintCurStats();
            cout << clock <<"'s:  A pag is calling at F"<< newPassenger.from_floor<< endl;
            Call(clock, newPassenger);
        }
        if (clock == e1.clockExpectAim ){
            cout <<endl << clock <<"'s:  Arrive at F" << e1.nowFloor<< " please get on and off" << endl;
            int nd = Depart(clock);
            int ne = Enter(clock);
            UpdateAim(clock);
            cout <<"       "<< nd<<" pags get off ___ "<< ne <<" pags get on "<<endl;
            PrintCurStats();
        }
        clock++;
    }
}

void SimBuilding::Call(int clock, cpassenger wp) {
        pwaitting[WaitCount()] = wp;
        电梯停止,呼叫直接过去
        if (e1.run_status == stop){
            e1.clockBegin = clock;
            正好在同一层
            if (wp.from_floor == e1.nowFloor ){
                //人要上
                if ( wp.to_floor > wp.from_floor){
                    e1.run_status = up;
                    e1.clockExpectAim = clock + timeRunaFloor*(wp.from_floor-e1.nowFloor);
                }
                //人要下
                else {
                    e1.run_status = down;
                    e1.clockExpectAim = clock + timeRunaFloor*(e1.nowFloor-wp.from_floor);
                }
            }
            ///人在上面叫
            else if (wp.from_floor > e1.nowFloor ){
                e1.run_status = up;
                e1.clockExpectAim = clock + timeRunaFloor*(wp.from_floor-e1.nowFloor);
            }
            ///人在下面叫
            else{
                e1.run_status = down;
                e1.clockExpectAim = clock + timeRunaFloor*(e1.nowFloor-wp.from_floor);
            }
        }
        电梯运动,有效呼叫改变clockExpectAim
        else{
            与电梯同向且在电梯行进方向前
            if (e1.run_status == up && wp.from_floor > e1.nowFloor && wp.to_floor > wp.from_floor){
                e1.exButton[wp.from_floor] = aim;
                ///根据最近停靠,改变clockExpectAim
                for (int i=e1.nowFloor; i<=BudfloorNum;i++)
                    if (e1.exButton[i] == aim || e1.exButton[i] == aim){
                        e1.clockExpectAim = (clock + e1.clockBegin + (e1.nowFloor-wp.from_floor)*timeRunaFloor)
                                            -((clock - e1.clockBegin)%timeRunaFloor);
                        break;
                    }
            }
            if (e1.run_status == up && wp.from_floor==BudfloorNum)
                e1.exButton[wp.from_floor] = aim;
            e1.exButton[wp.from_floor] = aim;
            if (e1.run_status == down && wp.from_floor < e1.nowFloor && wp.to_floor < wp.from_floor ){
                e1.exButton[wp.from_floor] = aim;
                for (int i=e1.nowFloor; i>=1;i--)
                    if ( e1.exButton[i] == aim){
                        e1.clockExpectAim = (clock + e1.clockBegin + (e1.nowFloor-wp.from_floor)*timeRunaFloor)
                                            -((clock - e1.clockBegin)%timeRunaFloor);
                        break;
                    }
            }
            if (e1.run_status == down && wp.from_floor==1)
                e1.exButton[wp.from_floor] = aim;
        }
}

void SimBuilding::UpdateAim(int clock) {
    ///电梯掉头,并选择同方向等待者,更新exButton
    if (e1.nowFloor == BudfloorNum || e1.CurCount()==0 && !Havpag(e1.nowFloor+1,BudfloorNum) ) {
        e1.run_status = down;
        e1.clockBegin =clock;

        for (int k=0;k<100;k++)
            if (pwaitting[k].isin == in &&pwaitting[k].to_floor < pwaitting[k].from_floor)
                e1.exButton[pwaitting[k].from_floor] = aim;

    }
    else if (e1.nowFloor == 1  || e1.CurCount()==0 && !Havpag(1,e1.nowFloor-1)) {
        e1.run_status = up;
        e1.clockBegin =clock;

        for (int k=0;k<100;k++)
            if (pwaitting[k].isin == in && pwaitting[k].to_floor > pwaitting[k].from_floor)
                e1.exButton[pwaitting[k].from_floor] = aim;

    }
    ///(是否Stop)
    if ( e1.CurCount()==0 && !Havpag(1,BudfloorNum))
        e1.run_status=stop;

    ///更改clockExpectAim(只要停靠就会更新)
    if (e1.run_status != stop){
        if (e1.run_status == down)
            for (int i=e1.nowFloor; i>=1;i--)
                if (e1.inButton[i] == aim || e1.exButton[i] == aim){
                    int aimF = i;
                    e1.clockExpectAim = clock + (e1.nowFloor-aimF)*timeRunaFloor
                                        -(clock - e1.clockBegin)%timeRunaFloor;
                    break;
                }
        if (e1.run_status == up)
            for (int i=e1.nowFloor; i<=BudfloorNum;i++)
                if (e1.inButton[i] == aim || e1.exButton[i] == aim){
                    int aimF = i;
                    e1.clockExpectAim = clock + (aimF-e1.nowFloor)*timeRunaFloor
                                        -(clock - e1.clockBegin)%timeRunaFloor;
                    break;
                }
    }
}

int SimBuilding::Enter(int clock) {
    int numEnter = 0;
    if (clock == e1.clockExpectAim){
        //遍历整栋楼等待的pag
        cpassenger wp;
        for (int i=0; i<100; i++){
            if (pwaitting[i].isin == in && pwaitting[i].from_floor == e1.nowFloor && e1.CurCount()<maxEleNum){
                numEnter++;
                wp = pwaitting[i];

                e1.exButton[wp.from_floor] = pass;
                e1.pin[e1.CurCount()]=pwaitting[i];   //该乘客上电梯
                e1.inButton[wp.to_floor]=aim;         //按目的楼层

                pwaitting[i].isin = out;  //相当于在等待队列中移除该乘客
            }
        }
    }
    Sort();
    return numEnter;
}

int SimBuilding::Depart(int clock) {
    int numDepart=0;
    if (clock == e1.clockExpectAim ) {
        //遍历电梯里的pag
        for (int i = 0; i < maxEleNum; i++) {
            if (e1.pin[i].isin == in && e1.pin[i].to_floor == e1.nowFloor) {
                numDepart++;
                phav[HavCount()] = e1.pin[i];
                e1.pin[i].isin = out;  //相当于在电梯中移除该乘客
                e1.inButton[e1.nowFloor] = pass;
            }
        }
    }
    Sort();
    return numDepart;
}

bool SimBuilding::Havpag(int fl, int fh) {    //某楼层有人返回true
    bool flag= false;
    for (int i=0; i< 100;i++)
        if (pwaitting[i].isin==in && (fl<=pwaitting[i].from_floor&&pwaitting[i].from_floor<=fh) ){
            flag = true;
            break;
        }
    return flag;
}

int SimBuilding::WaitCount() {
    int waitcount = 0;
    for (int i=0; i<100; i++)
        if (pwaitting[i].isin == in)
            waitcount++;
    return waitcount;
}

int SimBuilding::HavCount() {
    int havcount = 0;
    for (int i=0; i<100; i++)
        if (phav[i].isin == in)
            havcount++;
    return havcount;
}

void SimBuilding::PrintCurStats() {
    if (e1.run_status==stop) cout << "stop "<<endl;
    else if (e1.run_status==up) cout << "up "<<endl;
    else if (e1.run_status==down) cout << "down "<<endl;
    for (int i=BudfloorNum; i>=1; i--){
        if (i == e1.nowFloor){
            cout << "|$" ;
            for (int i=0;i<5-e1.CurCount()/2;i++) cout <<" ";
            for (int i=0;i<e1.CurCount();i++) cout <<"*";
            if (e1.CurCount()%2==0) for (int i=0;i<5-e1.CurCount()/2;i++) cout <<" ";
            else for (int i=0;i<4-e1.CurCount()/2;i++) cout <<" ";
            cout <<"$|"<<endl;
        }
        else cout << "|      " <<i<<"     |"<<endl;
    }
}

void SimBuilding::Move(int clock) {
    if (e1.run_status != stop && (clock - e1.clockBegin)%timeRunaFloor == 0 && (clock - e1.clockBegin)!=0){
        if (e1.run_status == up) e1.nowFloor++;
        else if (e1.run_status == down) e1.nowFloor--;
    }
}

void SimBuilding::Sort() {
    cpassenger wp,ip;
    for (int i=0;i<100;i++)
        if (pwaitting[i].isin == in ){
            wp=pwaitting[i];
            for (int j=0;j<100;j++){
                if (pwaitting[j].isin==out && j<i){
                    pwaitting[i]=pwaitting[j];
                    pwaitting[j] = wp;
                    break;
                }
            }
        }

    for (int i=0;i<10;i++)
        if (e1.pin[i].isin == in ){
            ip=e1.pin[i];
            for (int j=0;j<100;j++){
                if (e1.pin[i].isin==out && j<i){
                    e1.pin[i]=pwaitting[j];
                    e1.pin[i] = ip;
                    break;
                }
            }
        }
}

main.cpp

#include "Elevator.h"

int main() {
    SimBuilding sim;
    sim.RunSimulation();
}

效果

假设电梯运行时经过一层楼所用时间为3s
自定义的测试乘客,便于说明效果
0s时电梯停止,有人(在一楼,要去九楼)呼叫
在这里插入图片描述
0s时电梯停靠在一楼让乘客出入,并开始上行
在这里插入图片描述
4s时电梯上行,有人(在四楼,要去二楼)呼叫
在这里插入图片描述24s时电梯停靠在九楼让乘客出入,并开始下行
在这里插入图片描述39s时电梯停靠在四楼让乘客出入,并继续下行
在这里插入图片描述45s时电梯停靠在二楼让乘客出入,之后电梯停止
在这里插入图片描述

不足

写了两天,问题很多,不过再没时间耽误在这上面了,后面有空回头来优化吧。

  1. 电梯运行策略 这是给的是电梯直上直下,当乘客运行与电梯运行方向一致且在电梯前方,电梯就会停靠,比较符合现实直观,当然有待改进。
  2. 电梯数量 后面SimBuilding类中的运行过程的所有函数都是针对e1(写死了这块),导致无法声明更多的电梯,无法模拟一栋楼内多部电梯的合理调度。
  3. 模拟乘客 这里乘客的给定在代码中需要自己定义,要模拟大量乘客的话,效率极低。两种改进方法:1、加随机数 随机时刻生成随机状态乘客(所在楼层,目的楼层均随机)2、文件交互 将所有模拟乘客按指定格式记录在一个文本中,代码中添加与该外部文本交互的功能。
  4. 输出画面 输出窗口给出了所有特殊事件的明细(发生时刻,乘客行为,电梯状态),但是给人一种感觉,输出是对整个过程的记录而不是模拟运行(类似于动画那样)。当然这个实现动态画面要求就比较高了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值