web-dev-qa-db-fra.com

Structure de données pour le mécanisme d'élévateur

Cette question m’a été posée lors d’un entretien d’entreprise -.__ Quelle structure de données est efficace pour la mise en œuvre du mécanisme d’ascenseur?

Je ne parviens pas à trouver la structure de données efficace, même après beaucoup de recherches sur Google.

Je peux penser à la file d'attente prioritaire à mettre en œuvre. La file d'attente prioritaire est-elle une structure de données efficace ou une structure de données plus efficace pour la mise en œuvre du mécanisme d'ascenseur?

Merci! 

20
ritesh_NITW

Comme vous ne pouvez pas implémenter mécanismes dans un logiciel (bien que vous puissiez certainement les modéliser eux), je suppose que la question concerne le algorithme Elevator .

L'algorithme a l'air d'une simplicité trompeuse, mais il est étonnamment très difficile à mettre en œuvre, même avec un bon ensemble de structures de données en main. Une bonne structure à utiliser pour cet algorithme est constituée de trois files d'attente prioritaires:

  1. Pour la direction actuelle avec des entrées au-delà du point actuel,
  2. Pour la direction opposée, et
  3. pour la direction actuelle avant le point actuel.

Votre implémentation déciderait d’abord la direction, puis choisirait une file d’attente dans laquelle placer la paire demandée de valeurs {from, to}.

24
dasblinkenlight

Et si nous utilisions deux listes chaînées, une pour les demandes de mouvement vers le haut et une autre pour les demandes de mouvement vers le bas.

par exemple

Première demande: A) .si l'ascenseur est au 0e étage et une demande vient au 3e étage.

liste liée pour le mouvement à la hausse. 

3-> null.

liste liée pour le mouvement à la baisse. 

nul.

Deuxième demande: B). tandis que l'ascenseur s'est déplacé au 1er étage et une demande vient du 2ème étage pour un mouvement ascendant.

liste liée pour le mouvement à la hausse. 

2-> 3-> null

liste liée pour le mouvement à la baisse. 

nul.

Troisième demande: C) Supposons que 2 personnes entrent au 2e étage, une touche pour le 5e étage et une autre pour le 1er.

liste liée pour le mouvement à la hausse. 

3-> 5-> null

Remarque: Ici 2 a été supprimé de la liste chaînée ascendante car il a été atteint.

liste liée pour le mouvement à la baisse. 

1-> null.

d) Supposons qu'une personne entre au 3ème étage et appuie sur le bouton pour le 0ème étage

liste liée pour le mouvement à la hausse. 

5-> null

liste liée pour le mouvement à la baisse. 

1-> 0-> null.

Une fois que le 5ème étage a atteint la liste chaînée des demandes ascendante, il devient vide et la liste chaînée descendante peut être considérée pour le déplacement.

Si les deux la liste liée sont vides alors l'ascenseur serait au repos.

Je pense donc que la liste chaînée peut également constituer une structure de données efficace pour les ascenseurs.

12
sacrishi

Vous trouverez ci-dessous une façon de concevoir un système d’ascenseur. Chaque ascenseur utilise la file d'attente (il peut s'agir d'une file d'attente bloquante) pour stocker les demandes d'étage. Il existe également un ElevatorManager central qui surveille toutes les files d'attente d'ascenseurs et peut déléguer les demandes à un ascenseur en fonction de certaines règles commerciales. ElevatorManager a pour tâche de déléguer efficacement les demandes à l'élévateur concerné. Le pseudocode ci-dessous n'optimise pas l'algorithme de délégation, mais il montre comment une délégation réelle pourrait être effectuée vers une liste d'ascenseurs.

Classes nécessaires pour le système d'ascenseur:

ElevatorManager [Singleton - C’est le programme principal d’ascenseurs qui gérera n ascenseurs dans le bâtiment]
Membres:
Liste d'ascenseur
Queue of Floor.Request // Ceci maintient la demande pour les deux directions. Une amélioration pourrait consister à garder deux files d'attente, une pour chaque direction, mais cela augmenterait la complexité.
MIN_FLOOR
MAX_FLOOR
Opérations:
delgate ()
halt () // place tout le système d'ascenseur en mode maintenance ou arrête le fonctionnement


Ascenseur [Représente les ascenseurs individuels. Il pourrait y avoir n ascenseurs dans un bâtiment]
Membres:
File d'attente de l'étage // ceci doit être trié afin qu'une file d'attente PriorityQueue puisse être utilisée
Direction: Enum [Enum de direction - haut, bas, attente, ralenti, maintenance]
CurrentFloor: Floor
Opérations:
fonctionner()
déplacer vers le haut()
moveDown ()
porte ouverte()
ferme la porte()
callEmergencyLine ()
getDirection ()
getCurrentFloor ()
setInMaintenanceMode ()


Sol [Représente les étages individuels]
Membres:
Nombre de planchers
Demande de classe {
sol actuel
destinationFloor
Direction [haut, bas]
}
Opération:
monter()
descendre()

Certains des pseudocodes principaux pour les composants ci-dessus:

class Floor {
    goUp() {
        ElevatorManager.queue.offer(new Request(currentFloor, destinationFloor, up));
    }   

    goDown() {
        ElevatorManager.queue.offer(new Request(currentFloor, destinationFloor, down));
    }
}

ElevatorManager {
    delegate() {

        // Instead of using one object, we could use a list to track idle and elevators moving in same direction so that these list could be used for next requests in queue
        // but again to simplify pseudocode, I am using single objects instead of lists
        Elevator idleElevator; // track idle elevator
        Elevator elevatorMovingInSameDirection; // elevator moving in same direction as next request in main elevator manager queue 

        while(!halt()) { //keep delegating until powered down or whole system is halted through main controls

            if(queue.peek() != null) {

                Request req = queue.peek();
                boolean startAgain = false; // flag to start from beginning if the request is already pushed to one of the elevators queue during iterating elevators

                for(Elevator elevator : elevators) {

                    // first find if there is an elevator at current floor going in same direction as current request in queue
                    if(req.currentFloor == elevator.currentFloor && req.direction == elevator.direction) {
                        elevator.queue.offer(req.destinationFloor);
                        queue.poll(); // remove this request from Elevator Manager queue

                        startAgain = true;
                        break;
                    }

                    // check if this elevator is idle
                    if(elevator.direction == "idle")) {
                        idleElevator = elevator; // For this simple design, I am ok to overwrite idle elevator value and instead get the latest idle elevatior
                    }

                    // check if this elevator is moving in desired direction and elevator's current floor is behind desired floor in queue
                    if(elevator.direction == req.direction) {

                        // Make sure elevators moving in same direction should also be behind the floor where request is made
                        if(req.direction == "Up" && req.currentFloor - elevator.currentFloor > 0) {

                            elevatorMovingInSameDirection = elevator; // Same as above, it's ok to get this overwritten and instead get the latest elevator moving in same      direction
                        }

                        // Make sure elevators moving in same direction should also be behind the floor where request is made
                        if(req.direction == "Down" && req.currentFloor - elevator.currentFloor < 0) {
                            elevatorMovingInSameDirection = elevator;
                        }
                    }

                }

                // Only delegate to other floors if you could not find elevator going in same direction at same floor from where the request was made
                if(!startAgain && idleElevator != null) {
                    idleElevator.queue.offer(req.destinationFloor);
                    queue.poll();
                }

                // if we could neither find elevator at current floor nor idle elevator then send this request to elevator behind current Floor and moving in same direction as the request
                if(!startAgain && elevatorMovingInSameDirection != null) {
                    elevatorMovingInSameDirection.queue.offer(req.destinationFloor);
                    queue.poll();
                }


            }
        }
    }
}


Elevator {

    moveUp() {
        this.currentFloor += 1;
    }

    moveDown() {
        this.currentFloor -= 1;
    }

    operate() {

        while(queue.peek() != null) {

            Floor nextFloorInQueue = queue.peek();

            while(this.currentFloor != nextFloorInQueue.request.destinationFloor) {
                if(this.direction == "Up") {
                    moveUp();
                } else if(this.direction == "down") {
                    moveDown();
                }
            }

            queue.poll(); // remove the request from queue
            open(); //open door

            Direction backUpDirection = this.direction; //back up elevators direction to retrieve it later once dooor closes
            this.direction = "idle"; // set state to idle to let elevatorManager know that requests at current floor could be offered to this elevator queue

            Thread.sleep(10000); // sleep for 10 seconds so that people can leave elevator

            close(); // once people are out close door to move to next floor in queue
            this.direction = backUpDirection;
        }

        this.direction = "idle"; // once queue is empty set the direction to idle
    }
}

Il est également disponible sur mon Github: https://github.com/prabhash1785/Java/blob/master/ObjectOrientedDesign/src/com/prabhash/Java/design/objectoriented/elevator/ElevatorDesignWithPseudocode.md

2
Prabhash Rathore

Pour simplifier, considérons un système d’ascenseurs simple

Structure de données utilisée: Simple listes pour stocker le numéro de plancher, enums pour l'événement et l'état. 

Le système peut être configuré avec Event-State. Chaque aspect du comportement ou de l'environnement des utilisateurs doit être pris en compte pour décider quels scénarios peuvent être projetés sur l'ascenseur.

Events of the elevator : GOINGUP, GOINGDOWN, STOP 
States of the elevator : ONMOVE, WAITING (between door open and close), IDLE (serving no one), UNDERMAINTENANCE

Elevator movement is usually driven by two activites:
1. Press Up or Down key (before the entry gate of elevator) and wait for the elevator to come and serve you. (Press-And-Wait, say Paw) 
2. Enter inside the elevator and make request by pressing keys (Enter-And-Request, say EAR)

So it can said that Paw from outside and EAR from inside can decide the Hops of the elevator. But what about direction?

Two possible types of Paw: PAWup (press Up button) and PAWdown (press Down button)

Now, EAR can be any of the three types depending upon the users behavior. These are the critical challenges in deciding the algorithm: 
1.) Normal - same direction as Paw (wanted to go down and enter lower floor#) 
2.) Opposite - wanted to go down BUT enter higher floor#
3.) Indecisive - Do Nothing, no key press

Now comes all the important rules:
RULE 1: If at IDLE, use FCFS to decide between the DownList front and UpList front - whoever is oldest, serve it first to ensure less waiting time. 
RULE 2: When both lists (DownList and UpList) are empty, move elevator to IDLE state. 
RULE 3: Elevator state change GOINGUP->STOP clears that floor# from UpList. Similarly, GOINGDOWN->STOP clears that floor from DownList.
RULE 4: Absolute Zero Skipping: GOINGxxx serves as many floors in xxxList as possible. 
RULE 5: Elevator doesn't favour Opposite-EAR, and obviously can't serve Indecisive-EAR.
RULE 6: Elevator in UNDERMAINTENANCE state is shunned from all external signals.
RULE 7: In the event of Power-cuts or Fire, the elevator goes and stops at Lobby. Flooding??

To achieve RULE#5, GOINGDOWN clears all the lower floor# in DownList in ONE GO. Similarly, GOINGUP clears all the higher floor# in UpList.    

Lets discuss one scenario to clear the above concepts:
Say, an elevator is resting at floor 7 is at IDLE state, 
    DownList : 
    UpList : 

IDLE@7 - PAWdown@12 then PAWup@9 then PAWdown@13
    DownList : 12, 13 (older requests at lower index.Push new requests at front.)
    UpList : 9 
    Using RULE#2, in the above case, 
    Event: GOINGUP to Pick@12.  

WAITING@12  - 12 cleared following RULE#3

MeanWhile, PAWup@8 then PAWup@10 then PAWdown@10, so updated lists are:
    DownList : 13, 10 
    UpList : 9, 8, 10

So here, in the current situation, if the EAR is
1.) Normal, GOINGDOWN(towards new EAR) is triggered.
2.) Opposite/Indecisive, GOINGDOWN(towards 9) is triggered and add the new EAR in UpList. 

En utilisant les règles mentionnées ci-dessus, l'ascenseur continue son travail habituel. 

0
Saurav Sahu

Que diriez-vous d'avoir un tableau, où chaque entrée de tableau représente un étage. Lorsque l'utilisateur souhaite s'arrêter à un étage, il marque cette entrée dans la matrice, et l'ascenseur examinera la matrice et effacera l'entrée si elle indique quand l'ascenseur atteint cet étage. Similaire à l'algorithme de planification SCAN/CSAN. J'attends vos commentaires avec impatience

0
rgaut