Come si implementano uno stack e una coda in JavaScript?


741

Qual è il modo migliore per implementare uno stack e una coda in JavaScript?

Sto cercando di eseguire l'algoritmo di shunting yard e avrò bisogno di queste strutture di dati.

Risposte:


1347
var stack = [];
stack.push(2);       // stack is now [2]
stack.push(5);       // stack is now [2, 5]
var i = stack.pop(); // stack is now [2]
alert(i);            // displays 5

var queue = [];
queue.push(2);         // queue is now [2]
queue.push(5);         // queue is now [2, 5]
var i = queue.shift(); // queue is now [5]
alert(i);              // displays 2

tratto da " 9 suggerimenti javascript che potresti non conoscere "


218
Consiglierei cautela nell'uso di queue.shift. IIRC non è O (1), ma O (n) e potrebbe essere troppo lento se la coda diventa grande.
MAK

20
Direi che questo dipende dall'implementazione di JavaScript. Non credo sia definito nelle specifiche javascript.
Georg Schölly,

9
Vedi code.stephenmorley.org/javascript/queues per una semplice implementazione che migliora le prestazioni della coda.
Gili,

15
Per problemi di prestazioni della coda, vedi un bel confronto tra tre diversi tipi di comportamenti dello stack su jsperf.com/queue-push-unshift-vs-shift-pop - Ora se solo qualcuno fosse abbastanza gentile da includere un giro di quel jsperf che contiene lo script JS menzionato da @Gili ...
Nenotlep

3
Ho resuscitato il post del blog collegato in questa risposta poiché archive.org non è sempre il più performante. Ho aggiornato i collegamenti e le immagini in modo che funzionino ma non ho cambiato nient'altro.
Chev,

87

Javascript ha metodi push e pop, che operano su normali oggetti array Javascript.

Per le code, guarda qui:

http://safalra.com/web-design/javascript/queues/

Le code possono essere implementate in JavaScript utilizzando i metodi push e shift o i metodi unshift e pop dell'oggetto array. Sebbene questo sia un modo semplice per implementare le code, è molto inefficiente per le code di grandi dimensioni: a causa dei metodi che funzionano sugli array, i metodi shift e unshift spostano ogni elemento dell'array ogni volta che vengono chiamati.

Queue.js è un'implementazione della coda semplice ed efficiente per JavaScript la cui funzione di dequeue viene eseguita in tempo costante ammortizzato. Di conseguenza, per code più grandi, può essere significativamente più veloce rispetto all'utilizzo di array.


2
Con il link che hai condiviso aveva una funzionalità di controllo dei risultati del benchmark e non vedo miglioramenti delle prestazioni quando testato con Google Chrome versione 59. Queue.js non è coerente con la sua velocità ma Chrome era preety coerente con la sua velocità.
Shiljo Paulson,

Inoltre ho fatto una demo con queue.js, che, la funzione di dequeue non rimuove realmente l'elemento dalla coda, quindi mi chiedo se supponiamo che funzioni come funziona? In tal caso, come è possibile recuperare la nuova coda dopo aver rimosso la coda dall'elemento precedente? codepen.io/adamchenwei/pen/VxgNrX?editors=0001
Ezeewei

sembra che il dequeue in queue.js richieda anche memoria aggiuntiva poiché sta clonando l'array con slice.
Ja

Inoltre, l'array sottostante sta diventando sempre più grande con ogni elemento aggiunto. Anche se l'implementazione riduce di volta in volta le dimensioni dell'array, le dimensioni complessive aumentano.
Philipp Mitterer,

73

Array.

Pila:

var stack = [];

//put value on top of stack
stack.push(1);

//remove value from top of stack
var value = stack.pop();

Coda:

var queue = [];

//put value on end of queue
queue.push(1);

//Take first value from queue
var value = queue.shift();

1
Array.prototype.pop non rimuove il valore dall'alto (primo elemento) dell'array. Rimuove il valore dal basso (ultimo elemento) dell'array.
Michael Geller,

21
@MichaelGeller La parte superiore della pila è l' ultimo elemento dell'array. I metodi push e pop dell'array si comportano proprio come uno stack.
mrdommyg,

@mrdommyg Array.prototype.pop rimuove l' ultimo elemento dell'array (consultare developer.mozilla.org/en/docs/Web/JavaScript/Reference/… ). Ultimo in questo contesto significa l'elemento con l'indice più alto. Un array in JS non ha nulla a che fare con uno stack. Non è uno stack solo perché ha un metodo pop. Pop significa semplicemente "rimuovere l'ultimo elemento e restituirlo". Ovviamente puoi simulare la funzionalità di uno stack con un array, ma un array non è ancora uno stack per definizione. È ancora un elenco (un oggetto "list like" secondo MDN).
Michael Geller,

5
@MichaelGeller Il comportamento di uno stack è "first in, last out". Se lo implementi usando un array in JavaScript con i suoi metodi pushe pop, quindi il problema è stato risolto. Non vedo davvero il tuo punto qui.
Rax Weber,

2
@MichaelGeller Uno stack è concettuale. Un array JS è (tra le altre cose) per definizione uno stack in virtù dell'implementazione della semantica dello stack. Solo perché implementa anche la semantica dell'array non cambia questo. È possibile utilizzare un array JS come uno stack pronto all'uso e in quel contesto ciò che si spinge e si apre è l'elemento "top".
Hans,

32

Se si desidera creare strutture di dati personalizzate, è possibile creare le proprie:

var Stack = function(){
  this.top = null;
  this.size = 0;
};

var Node = function(data){
  this.data = data;
  this.previous = null;
};

Stack.prototype.push = function(data) {
  var node = new Node(data);

  node.previous = this.top;
  this.top = node;
  this.size += 1;
  return this.top;
};

Stack.prototype.pop = function() {
  temp = this.top;
  this.top = this.top.previous;
  this.size -= 1;
  return temp;
};

E per la coda:

var Queue = function() {
  this.first = null;
  this.size = 0;
};

var Node = function(data) {
  this.data = data;
  this.next = null;
};

Queue.prototype.enqueue = function(data) {
  var node = new Node(data);

  if (!this.first){
    this.first = node;
  } else {
    n = this.first;
    while (n.next) {
      n = n.next;
    }
    n.next = node;
  }

  this.size += 1;
  return node;
};

Queue.prototype.dequeue = function() {
  temp = this.first;
  this.first = this.first.next;
  this.size -= 1;
  return temp;
};

13
Per evitare la necessità di iterare sull'intera cosa per aggiungere alla fine, memorizzare un riferimento all'ultima tramite this.last = node;
Perkins,

9
Non implementare mai una coda come questa a meno che tu non abbia una buona ragione per farlo ... mentre potrebbe sembrare logicamente corretto, le CPU non funzionano secondo le astrazioni umane. L'iterazione su una struttura di dati con puntatori in tutto il luogo comporterà la mancanza di cache nella CPU, a differenza di un array sequenziale che è altamente efficiente. blog.davidecoppola.com/2014/05/… Le CPU odiano i puntatori con una passione ardente: sono probabilmente la causa numero 1 dei mancati cache e devono accedere alla memoria dalla RAM.
Centril,

1
questa è una soluzione allettante, ma non vedo che i messaggi creati Nodevengono eliminati quando si fa il popping / dequeue ... non si limiteranno a stare seduti a memoria di hogging fino a quando il browser non si blocca?
cneuro,

5
@cneuro A differenza del C ++, JavaScript è un linguaggio di raccolta dati inutili. Ha una deleteparola chiave, ma è utile solo per contrassegnare una proprietà di un oggetto come non presente, il che è diverso dal semplice assegnamento undefinedalla proprietà . JavaScript ha anche un newoperatore, ma viene usato solo per impostare thisun nuovo oggetto vuoto quando si chiama una funzione. In C ++ devi accoppiare ciascuno newcon a delete, ma non in JavaScript perché GC. Per smettere di usare la memoria in JavaScript, basta smettere di fare riferimento all'oggetto e alla fine verrà recuperato.
binki,

Non è anche necessario controllare uno stack per overflow impostando una dimensione massima dello stack?
ape il

16

La mia implementazione Stacke QueueutilizzoLinked List

// Linked List
function Node(data) {
  this.data = data;
  this.next = null;
}

// Stack implemented using LinkedList
function Stack() {
  this.top = null;
}

Stack.prototype.push = function(data) {
  var newNode = new Node(data);

  newNode.next = this.top; //Special attention
  this.top = newNode;
}

Stack.prototype.pop = function() {
  if (this.top !== null) {
    var topItem = this.top.data;
    this.top = this.top.next;
    return topItem;
  }
  return null;
}

Stack.prototype.print = function() {
  var curr = this.top;
  while (curr) {
    console.log(curr.data);
    curr = curr.next;
  }
}

// var stack = new Stack();
// stack.push(3);
// stack.push(5);
// stack.push(7);
// stack.print();

// Queue implemented using LinkedList
function Queue() {
  this.head = null;
  this.tail = null;
}

Queue.prototype.enqueue = function(data) {
  var newNode = new Node(data);

  if (this.head === null) {
    this.head = newNode;
    this.tail = newNode;
  } else {
    this.tail.next = newNode;
    this.tail = newNode;
  }
}

Queue.prototype.dequeue = function() {
  var newNode;
  if (this.head !== null) {
    newNode = this.head.data;
    this.head = this.head.next;
  }
  return newNode;
}

Queue.prototype.print = function() {
  var curr = this.head;
  while (curr) {
    console.log(curr.data);
    curr = curr.next;
  }
}

var queue = new Queue();
queue.enqueue(3);
queue.enqueue(5);
queue.enqueue(7);
queue.print();
queue.dequeue();
queue.dequeue();
queue.print();


10

Lo spostamento dell'array Javascript () è lento soprattutto quando si tengono molti elementi. Conosco due modi per implementare la coda con complessità O (1) ammortizzata.

Il primo consiste nell'utilizzare il buffer circolare e il raddoppio della tabella. L'ho implementato prima. Puoi vedere il mio codice sorgente qui https://github.com/kevyuu/rapid-queue

Il secondo modo è usando due stack. Questo è il codice per la coda con due stack

function createDoubleStackQueue() {
var that = {};
var pushContainer = [];
var popContainer = [];

function moveElementToPopContainer() {
    while (pushContainer.length !==0 ) {
        var element = pushContainer.pop();
        popContainer.push(element);
    }
}

that.push = function(element) {
    pushContainer.push(element);
};

that.shift = function() {
    if (popContainer.length === 0) {
        moveElementToPopContainer();
    }
    if (popContainer.length === 0) {
        return null;
    } else {
        return popContainer.pop();
    }
};

that.front = function() {
    if (popContainer.length === 0) {
        moveElementToPopContainer();
    }
    if (popContainer.length === 0) {
        return null;
    }
    return popContainer[popContainer.length - 1];
};

that.length = function() {
    return pushContainer.length + popContainer.length;
};

that.isEmpty = function() {
    return (pushContainer.length + popContainer.length) === 0;
};

return that;}

Questo è il confronto delle prestazioni usando jsPerf

CircularQueue.shift () vs Array.shift ()

http://jsperf.com/rapidqueue-shift-vs-array-shift

Come puoi vedere, è molto più veloce con un set di dati di grandi dimensioni


8

Esistono diversi modi in cui è possibile implementare stack e code in Javascript. La maggior parte delle risposte sopra sono implementazioni piuttosto superficiali e proverei a implementare qualcosa di più leggibile (usando le nuove funzionalità di sintassi di es6) e robusto.

Ecco l'implementazione dello stack:

class Stack {
  constructor(...items){
    this._items = []

    if(items.length>0)
      items.forEach(item => this._items.push(item) )

  }

  push(...items){
    //push item to the stack
     items.forEach(item => this._items.push(item) )
     return this._items;

  }

  pop(count=0){
    //pull out the topmost item (last item) from stack
    if(count===0)
      return this._items.pop()
     else
       return this._items.splice( -count, count )
  }

  peek(){
    // see what's the last item in stack
    return this._items[this._items.length-1]
  }

  size(){
    //no. of items in stack
    return this._items.length
  }

  isEmpty(){
    // return whether the stack is empty or not
    return this._items.length==0
  }

  toArray(){
    return this._items;
  }
}

Ed è così che puoi usare lo stack:

let my_stack = new Stack(1,24,4);
// [1, 24, 4]
my_stack.push(23)
//[1, 24, 4, 23]
my_stack.push(1,2,342);
//[1, 24, 4, 23, 1, 2, 342]
my_stack.pop();
//[1, 24, 4, 23, 1, 2]
my_stack.pop(3)
//[1, 24, 4]
my_stack.isEmpty()
// false
my_stack.size();
//3

Se desideri vedere la descrizione dettagliata di questa implementazione e come può essere ulteriormente migliorata, puoi leggere qui: http://jschap.com/data-structures-in-javascript-stack/

Ecco il codice per l'implementazione della coda in es6:

class Queue{
 constructor(...items){
   //initialize the items in queue
   this._items = []
   // enqueuing the items passed to the constructor
   this.enqueue(...items)
 }

  enqueue(...items){
    //push items into the queue
    items.forEach( item => this._items.push(item) )
    return this._items;
  }

  dequeue(count=1){
    //pull out the first item from the queue
    this._items.splice(0,count);
    return this._items;
  }

  peek(){
    //peek at the first item from the queue
    return this._items[0]
  }

  size(){
    //get the length of queue
    return this._items.length
  }

  isEmpty(){
    //find whether the queue is empty or no
    return this._items.length===0
  }
}

Ecco come è possibile utilizzare questa implementazione:

let my_queue = new Queue(1,24,4);
// [1, 24, 4]
my_queue.enqueue(23)
//[1, 24, 4, 23]
my_queue.enqueue(1,2,342);
//[1, 24, 4, 23, 1, 2, 342]
my_queue.dequeue();
//[24, 4, 23, 1, 2, 342]
my_queue.dequeue(3)
//[1, 2, 342]
my_queue.isEmpty()
// false
my_queue.size();
//3

Per seguire il tutorial completo su come sono state implementate queste strutture di dati e come possono essere ulteriormente migliorate, potresti voler passare attraverso la serie "Giocare con le strutture di dati in javascript" su jschap.com. Ecco i link per le code: http://jschap.com/playing-data-structures-javascript-queues/


7

Puoi usare la tua classe personalizzata in base al concetto, qui lo snippet di codice che puoi usare per fare le cose

/*
*   Stack implementation in JavaScript
*/



function Stack() {
  this.top = null;
  this.count = 0;

  this.getCount = function() {
    return this.count;
  }

  this.getTop = function() {
    return this.top;
  }

  this.push = function(data) {
    var node = {
      data: data,
      next: null
    }

    node.next = this.top;
    this.top = node;

    this.count++;
  }

  this.peek = function() {
    if (this.top === null) {
      return null;
    } else {
      return this.top.data;
    }
  }

  this.pop = function() {
    if (this.top === null) {
      return null;
    } else {
      var out = this.top;
      this.top = this.top.next;
      if (this.count > 0) {
        this.count--;
      }

      return out.data;
    }
  }

  this.displayAll = function() {
    if (this.top === null) {
      return null;
    } else {
      var arr = new Array();

      var current = this.top;
      //console.log(current);
      for (var i = 0; i < this.count; i++) {
        arr[i] = current.data;
        current = current.next;
      }

      return arr;
    }
  }
}

e per controllarlo usa la tua console e prova queste righe una per una.

>> var st = new Stack();

>> st.push("BP");

>> st.push("NK");

>> st.getTop();

>> st.getCount();

>> st.displayAll();

>> st.pop();

>> st.displayAll();

>> st.getTop();

>> st.peek();

2
Downvote per una convenzione di denominazione: metodo che inizia con un capitale assunto come costruttore.
Pavlo,

6
/*------------------------------------------------------------------ 
 Defining Stack Operations using Closures in Javascript, privacy and
 state of stack operations are maintained

 @author:Arijt Basu
 Log: Sun Dec 27, 2015, 3:25PM
 ------------------------------------------------------------------- 
 */
var stackControl = true;
var stack = (function(array) {
        array = [];
        //--Define the max size of the stack
        var MAX_SIZE = 5;

        function isEmpty() {
            if (array.length < 1) console.log("Stack is empty");
        };
        isEmpty();

        return {

            push: function(ele) {
                if (array.length < MAX_SIZE) {
                    array.push(ele)
                    return array;
                } else {
                    console.log("Stack Overflow")
                }
            },
            pop: function() {
                if (array.length > 1) {
                    array.pop();
                    return array;
                } else {
                    console.log("Stack Underflow");
                }
            }

        }
    })()
    // var list = 5;
    // console.log(stack(list))
if (stackControl) {
    console.log(stack.pop());
    console.log(stack.push(3));
    console.log(stack.push(2));
    console.log(stack.pop());
    console.log(stack.push(1));
    console.log(stack.pop());
    console.log(stack.push(38));
    console.log(stack.push(22));
    console.log(stack.pop());
    console.log(stack.pop());
    console.log(stack.push(6));
    console.log(stack.pop());
}
//End of STACK Logic

/* Defining Queue operations*/

var queue = (function(array) {
    array = [];
    var reversearray;
    //--Define the max size of the stack
    var MAX_SIZE = 5;

    function isEmpty() {
        if (array.length < 1) console.log("Queue is empty");
    };
    isEmpty();

    return {
        insert: function(ele) {
            if (array.length < MAX_SIZE) {
                array.push(ele)
                reversearray = array.reverse();
                return reversearray;
            } else {
                console.log("Queue Overflow")
            }
        },
        delete: function() {
            if (array.length > 1) {
                //reversearray = array.reverse();
                array.pop();
                return array;
            } else {
                console.log("Queue Underflow");
            }
        }
    }



})()

console.log(queue.insert(5))
console.log(queue.insert(3))
console.log(queue.delete(3))

5

Altrimenti è possibile utilizzare due array per implementare la struttura dei dati della coda.

var temp_stack = new Array();
var stack = new Array();

temp_stack.push(1);
temp_stack.push(2);
temp_stack.push(3);

Se ora pop gli elementi, l'output sarà 3,2,1. Ma vogliamo la struttura FIFO in modo da poter fare quanto segue.

stack.push(temp_stack.pop());
stack.push(temp_stack.pop());
stack.push(temp_stack.pop());

stack.pop(); //Pop out 1
stack.pop(); //Pop out 2
stack.pop(); //Pop out 3

1
Funziona solo se non hai mai pushpop
provato

5

Ecco un'implementazione della coda abbastanza semplice con due obiettivi:

  • A differenza di array.shift (), sai che questo metodo di dequeue richiede tempo costante (O (1)).
  • Per migliorare la velocità, questo approccio utilizza molte meno allocazioni rispetto all'approccio dell'elenco collegato.

L'implementazione dello stack condivide solo il secondo obiettivo.

// Queue
function Queue() {
        this.q = new Array(5);
        this.first = 0;
        this.size = 0;
}
Queue.prototype.enqueue = function(a) {
        var other;
        if (this.size == this.q.length) {
                other = new Array(this.size*2);
                for (var i = 0; i < this.size; i++) {
                        other[i] = this.q[(this.first+i)%this.size];
                }
                this.first = 0;
                this.q = other;
        }
        this.q[(this.first+this.size)%this.q.length] = a;
        this.size++;
};
Queue.prototype.dequeue = function() {
        if (this.size == 0) return undefined;
        this.size--;
        var ret = this.q[this.first];
        this.first = (this.first+1)%this.q.length;
        return ret;
};
Queue.prototype.peek = function() { return this.size > 0 ? this.q[this.first] : undefined; };
Queue.prototype.isEmpty = function() { return this.size == 0; };

// Stack
function Stack() {
        this.s = new Array(5);
        this.size = 0;
}
Stack.prototype.push = function(a) {
        var other;
    if (this.size == this.s.length) {
            other = new Array(this.s.length*2);
            for (var i = 0; i < this.s.length; i++) other[i] = this.s[i];
            this.s = other;
    }
    this.s[this.size++] = a;
};
Stack.prototype.pop = function() {
        if (this.size == 0) return undefined;
        return this.s[--this.size];
};
Stack.prototype.peek = function() { return this.size > 0 ? this.s[this.size-1] : undefined; };

5

L'implementazione dello stack è banale, come spiegato nelle altre risposte.

Tuttavia, non ho trovato risposte soddisfacenti in questo thread per l'implementazione di una coda in JavaScript, quindi ho creato la mia.

Esistono tre tipi di soluzioni in questo thread:

  • Array - La peggiore soluzione, usando array.shift() su un array di grandi dimensioni è molto inefficiente.
  • Elenchi collegati: è O (1) ma l'utilizzo di un oggetto per ogni elemento è un po 'eccessivo, specialmente se ce ne sono molti e sono piccoli, come la memorizzazione di numeri.
  • Array di turni ritardati: consiste nell'associare un indice all'array. Quando un elemento viene rimosso dalla coda, l'indice avanza. Quando l'indice raggiunge il centro dell'array, l'array viene suddiviso in due per rimuovere la prima metà.

Gli array a turni ritardati sono la soluzione più soddisfacente nella mia mente, ma conservano comunque tutto in un array contiguo di grandi dimensioni che può essere problematico e l'applicazione vacillerà quando l'array viene suddiviso.

Ho realizzato un'implementazione usando elenchi collegati di piccoli array (massimo 1000 elementi ciascuno). Le matrici si comportano come matrici a turni ritardate, tranne per il fatto che non vengono mai suddivise: quando ogni elemento dell'array viene rimosso, l'array viene semplicemente scartato.

Il pacchetto è su npm con funzionalità di base FIFO, l'ho appena spinto di recente. Il codice è diviso in due parti.

Ecco la prima parte

/** Queue contains a linked list of Subqueue */
class Subqueue <T> {
  public full() {
    return this.array.length >= 1000;
  }

  public get size() {
    return this.array.length - this.index;
  }

  public peek(): T {
    return this.array[this.index];
  }

  public last(): T {
    return this.array[this.array.length-1];
  }

  public dequeue(): T {
    return this.array[this.index++];
  }

  public enqueue(elem: T) {
    this.array.push(elem);
  }

  private index: number = 0;
  private array: T [] = [];

  public next: Subqueue<T> = null;
}

Ed ecco la Queueclasse principale :

class Queue<T> {
  get length() {
    return this._size;
  }

  public push(...elems: T[]) {
    for (let elem of elems) {
      if (this.bottom.full()) {
        this.bottom = this.bottom.next = new Subqueue<T>();
      }
      this.bottom.enqueue(elem);
    }

    this._size += elems.length;
  }

  public shift(): T {
    if (this._size === 0) {
      return undefined;
    }

    const val = this.top.dequeue();
    this._size--;
    if (this._size > 0 && this.top.size === 0 && this.top.full()) {
      // Discard current subqueue and point top to the one after
      this.top = this.top.next;
    }
    return val;
  }

  public peek(): T {
    return this.top.peek();
  }

  public last(): T {
    return this.bottom.last();
  }

  public clear() {
    this.bottom = this.top = new Subqueue();
    this._size = 0;
  }

  private top: Subqueue<T> = new Subqueue();
  private bottom: Subqueue<T> = this.top;
  private _size: number = 0;
}

Le annotazioni di tipo ( : X) possono essere facilmente rimosse per ottenere il codice javascript ES6.


4

Se capisci gli stack con le funzioni push () e pop (), allora la coda è solo per fare una di queste operazioni in senso opposto. L'opposto di push () è unshift () e opposto di pop () es shift (). Poi:

//classic stack
var stack = [];
stack.push("first"); // push inserts at the end
stack.push("second");
stack.push("last");
stack.pop(); //pop takes the "last" element

//One way to implement queue is to insert elements in the oposite sense than a stack
var queue = [];
queue.unshift("first"); //unshift inserts at the beginning
queue.unshift("second");
queue.unshift("last");
queue.pop(); //"first"

//other way to do queues is to take the elements in the oposite sense than stack
var queue = [];
queue.push("first"); //push, as in the stack inserts at the end
queue.push("second");
queue.push("last");
queue.shift(); //but shift takes the "first" element

Un avvertimento per coloro che scrivono software ad alte prestazioni. Il .shift()metodo non è un'implementazione della coda corretta. È O (n) anziché O (1) e sarà lento per le code di grandi dimensioni.
Rudi Kershaw,

3

Ecco la versione dell'elenco collegato di una coda che include anche l'ultimo nodo, come suggerito da @perkins e come è più appropriato.

// QUEUE Object Definition

var Queue = function() {
  this.first = null;
  this.last = null;
  this.size = 0;
};

var Node = function(data) {
  this.data = data;
  this.next = null;
};

Queue.prototype.enqueue = function(data) {
  var node = new Node(data);

  if (!this.first){ // for empty list first and last are the same
    this.first = node;
    this.last = node;
  } else { // otherwise we stick it on the end
    this.last.next=node;
    this.last=node;
  }

  this.size += 1;
  return node;
};

Queue.prototype.dequeue = function() {
  if (!this.first) //check for empty list
    return null;

  temp = this.first; // grab top of list
  if (this.first==this.last) {
    this.last=null;  // when we need to pop the last one
  }
  this.first = this.first.next; // move top of list down
  this.size -= 1;
  return temp;
};

In dequeue, dovresti invece restituire temp.data. Perché è quello che è stato messo in coda.
Not-a-robot,

3

Se stai cercando l'implementazione OOP ES6 della struttura di dati Stack e Queue con alcune operazioni di base (basate su elenchi collegati), potrebbe apparire così:

Queue.js

import LinkedList from '../linked-list/LinkedList';

export default class Queue {
  constructor() {
    this.linkedList = new LinkedList();
  }

  isEmpty() {
    return !this.linkedList.tail;
  }

  peek() {
    if (!this.linkedList.head) {
      return null;
    }

    return this.linkedList.head.value;
  }

  enqueue(value) {
    this.linkedList.append(value);
  }

  dequeue() {
    const removedHead = this.linkedList.deleteHead();
    return removedHead ? removedHead.value : null;
  }

  toString(callback) {
    return this.linkedList.toString(callback);
  }
}

Stack.js

import LinkedList from '../linked-list/LinkedList';

export default class Stack {
  constructor() {
    this.linkedList = new LinkedList();
  }

  /**
   * @return {boolean}
   */
  isEmpty() {
    return !this.linkedList.tail;
  }

  /**
   * @return {*}
   */
  peek() {
    if (!this.linkedList.tail) {
      return null;
    }

    return this.linkedList.tail.value;
  }

  /**
   * @param {*} value
   */
  push(value) {
    this.linkedList.append(value);
  }

  /**
   * @return {*}
   */
  pop() {
    const removedTail = this.linkedList.deleteTail();
    return removedTail ? removedTail.value : null;
  }

  /**
   * @return {*[]}
   */
  toArray() {
    return this.linkedList
      .toArray()
      .map(linkedListNode => linkedListNode.value)
      .reverse();
  }

  /**
   * @param {function} [callback]
   * @return {string}
   */
  toString(callback) {
    return this.linkedList.toString(callback);
  }
}

E l'implementazione di LinkedList utilizzata per Stack e Queue negli esempi precedenti può essere trovata qui su GitHub .


2

Nessuna matrice

//Javascript stack linked list data structure (no array)

function node(value, noderef) {
    this.value = value;
    this.next = noderef;
}
function stack() {
    this.push = function (value) {
        this.next = this.first;
        this.first = new node(value, this.next);
    }
    this.pop = function () {
        var popvalue = this.first.value;
        this.first = this.first.next;
        return popvalue;
    }
    this.hasnext = function () {
        return this.next != undefined;
    }
    this.isempty = function () {
        return this.first == undefined;
    }

}

//Javascript stack linked list data structure (no array)
function node(value, noderef) {
    this.value = value;
    this.next = undefined;
}
function queue() {
    this.enqueue = function (value) {
        this.oldlast = this.last;
        this.last = new node(value);
        if (this.isempty())
            this.first = this.last;
        else 
           this.oldlast.next = this.last;
    }
    this.dequeue = function () {
        var queuvalue = this.first.value;
        this.first = this.first.next;
        return queuvalue;
    }
    this.hasnext = function () {
        return this.first.next != undefined;
    }
    this.isempty = function () {
        return this.first == undefined;
    }

}

Come posso eseguire determinate funzioni interne come push pop?
Chandan Kumar,

2

La normale struttura dell'array in Javascript è uno stack (primo in entrata, ultimo in uscita) e può anche essere usato come coda (primo in entrata, primo in uscita) a seconda delle chiamate effettuate.

Controlla questo link per vedere come fare in modo che un array si comporti come una coda:

code


2

Saluti,

In Javascript l'implementazione di stack e code è la seguente:

Stack: uno stack è un contenitore di oggetti che vengono inseriti e rimossi secondo il principio dell'ultimo in entrata (LIFO).

  • Push: il metodo aggiunge uno o più elementi alla fine di un array e restituisce la nuova lunghezza dell'array.
  • Pop: il metodo rimuove l'ultimo elemento da un array e restituisce quell'elemento.

Coda: una coda è un contenitore di oggetti (una raccolta lineare) che vengono inseriti e rimossi secondo il principio del primo in primo (FIFO).

  • Unshift: il metodo aggiunge uno o più elementi all'inizio di un array.

  • Maiusc: il metodo rimuove il primo elemento da un array.

let stack = [];
 stack.push(1);//[1]
 stack.push(2);//[1,2]
 stack.push(3);//[1,2,3]
 
console.log('It was inserted 1,2,3 in stack:', ...stack);

stack.pop(); //[1,2]
console.log('Item 3 was removed:', ...stack);

stack.pop(); //[1]
console.log('Item 2 was removed:', ...stack);


let queue = [];
queue.push(1);//[1]
queue.push(2);//[1,2]
queue.push(3);//[1,2,3]

console.log('It was inserted 1,2,3 in queue:', ...queue);

queue.shift();// [2,3]
console.log('Item 1 was removed:', ...queue);

queue.shift();// [3]
console.log('Item 2 was removed:', ...queue);


1
  var x = 10; 
  var y = 11; 
  var Queue = new Array();
  Queue.unshift(x);
  Queue.unshift(y);

  console.log(Queue)
  // Output [11, 10]

  Queue.pop()
  console.log(Queue)
  // Output [11]

1

Mi sembra che l'array integrato vada bene per uno stack. Se vuoi una coda in TypeScript ecco un'implementazione

/**
 * A Typescript implementation of a queue.
 */
export default class Queue {

  private queue = [];
  private offset = 0;

  constructor(array = []) {
    // Init the queue using the contents of the array
    for (const item of array) {
      this.enqueue(item);
    }
  }

  /**
   * @returns {number} the length of the queue.
   */
  public getLength(): number {
    return (this.queue.length - this.offset);
  }

  /**
   * @returns {boolean} true if the queue is empty, and false otherwise.
   */
  public isEmpty(): boolean {
    return (this.queue.length === 0);
  }

  /**
   * Enqueues the specified item.
   *
   * @param item - the item to enqueue
   */
  public enqueue(item) {
    this.queue.push(item);
  }

  /**
   *  Dequeues an item and returns it. If the queue is empty, the value
   * {@code null} is returned.
   *
   * @returns {any}
   */
  public dequeue(): any {
    // if the queue is empty, return immediately
    if (this.queue.length === 0) {
      return null;
    }

    // store the item at the front of the queue
    const item = this.queue[this.offset];

    // increment the offset and remove the free space if necessary
    if (++this.offset * 2 >= this.queue.length) {
      this.queue = this.queue.slice(this.offset);
      this.offset = 0;
    }

    // return the dequeued item
    return item;
  };

  /**
   * Returns the item at the front of the queue (without dequeuing it).
   * If the queue is empty then {@code null} is returned.
   *
   * @returns {any}
   */
  public peek(): any {
    return (this.queue.length > 0 ? this.queue[this.offset] : null);
  }

}

Ed ecco un Jesttest per questo

it('Queue', () => {
  const queue = new Queue();
  expect(queue.getLength()).toBe(0);
  expect(queue.peek()).toBeNull();
  expect(queue.dequeue()).toBeNull();

  queue.enqueue(1);
  expect(queue.getLength()).toBe(1);
  queue.enqueue(2);
  expect(queue.getLength()).toBe(2);
  queue.enqueue(3);
  expect(queue.getLength()).toBe(3);

  expect(queue.peek()).toBe(1);
  expect(queue.getLength()).toBe(3);
  expect(queue.dequeue()).toBe(1);
  expect(queue.getLength()).toBe(2);

  expect(queue.peek()).toBe(2);
  expect(queue.getLength()).toBe(2);
  expect(queue.dequeue()).toBe(2);
  expect(queue.getLength()).toBe(1);

  expect(queue.peek()).toBe(3);
  expect(queue.getLength()).toBe(1);
  expect(queue.dequeue()).toBe(3);
  expect(queue.getLength()).toBe(0);

  expect(queue.peek()).toBeNull();
  expect(queue.dequeue()).toBeNull();
});

Spero che qualcuno lo ritenga utile,

Saluti,

Stu


0

Crea una coppia di classi che forniscano i vari metodi di ciascuna di queste strutture di dati (push, pop, peek, ecc.). Ora implementa i metodi. Se hai familiarità con i concetti alla base di stack / coda, questo dovrebbe essere piuttosto semplice. È possibile implementare lo stack con un array e una coda con un elenco collegato, sebbene ci siano certamente altri modi per farlo. Javascript lo renderà facile, perché è tipizzato debolmente, quindi non devi nemmeno preoccuparti dei tipi generici, cosa che dovresti fare se lo implementassi in Java o C #.


0

Ecco la mia implementazione di stack.

function Stack() {
this.dataStore = [];
this.top = 0;
this.push = push;
this.pop = pop;
this.peek = peek;
this.clear = clear;
this.length = length;
}
function push(element) {
this.dataStore[this.top++] = element;
}
function peek() {
return this.dataStore[this.top-1];
}
function pop() {
return this.dataStore[--this.top];
}
function clear() {
this.top = 0;
}
function length() {
return this.top;
}

var s = new Stack();
s.push("David");
s.push("Raymond");
s.push("Bryan");
console.log("length: " + s.length());
console.log(s.peek());

0

puoi utilizzare WeakMaps per l'implementazione della proprietà privata nella classe ES6 e i vantaggi delle proprietà e dei metodi String nel linguaggio JavaScript come di seguito:

const _items = new WeakMap();

class Stack {
  constructor() {
    _items.set(this, []);
  }

push(obj) {
  _items.get(this).push(obj);
}

pop() {
  const L = _items.get(this).length;
  if(L===0)
    throw new Error('Stack is empty');
  return _items.get(this).pop();
}

peek() {
  const items = _items.get(this);
  if(items.length === 0)
    throw new Error ('Stack is empty');
  return items[items.length-1];
}

get count() {
  return _items.get(this).length;
}
}

const stack = new Stack();

//now in console:
//stack.push('a')
//stack.push(1)
//stack.count   => 2
//stack.peek()  => 1
//stack.pop()   => 1
//stack.pop()   => "a"
//stack.count   => 0
//stack.pop()   => Error Stack is empty

0

Costruisci una coda usando due pile.

O (1) per entrambe le operazioni di accodamento e dequeue.

class Queue {
  constructor() {
    this.s1 = []; // in
    this.s2 = []; // out
  }

  enqueue(val) {
    this.s1.push(val);
  }

  dequeue() {
    if (this.s2.length === 0) {
      this._move();
    }

    return this.s2.pop(); // return undefined if empty
  }

  _move() {
    while (this.s1.length) {
      this.s2.push(this.s1.pop());
    }
  }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.