Como você implementa uma pilha e uma fila em JavaScript?


741

Qual é a melhor maneira de implementar uma pilha e uma fila em JavaScript?

Eu estou olhando para fazer o algoritmo shunting-yard e vou precisar dessas estruturas de dados.

Respostas:


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

retirado de " 9 dicas de javascript que você talvez não saiba "


218
Eu recomendaria cautela ao usar o queue.shift. IIRC não é O (1), mas O (n) e pode ser muito lento se a fila ficar grande.
MAK

20
Eu diria que isso depende da implementação do javascript. Eu não acho que é definido na especificação de javascript.
Georg Schölly 19/10/2009

9
Consulte code.stephenmorley.org/javascript/queues para uma implementação simples que melhora o desempenho da fila.
Gili

15
Para problemas de desempenho da fila, consulte uma boa comparação de três tipos diferentes de comportamentos de pilha em jsperf.com/queue-push-unshift-vs-shift-pop - Agora, se apenas alguém fosse bom o suficiente para incluir uma revisão desse jsperf que seria conter o script JS que @Gili mencionado ...
Nenotlep

3
Ressuscitei a postagem do blog vinculada nesta resposta, pois o archive.org nem sempre é o mais eficiente. Atualizei links e imagens para que funcionem, mas não mudei mais nada.
Chev

87

O Javascript possui métodos push e pop, que operam em objetos comuns da matriz Javascript.

Para filas, veja aqui:

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

As filas podem ser implementadas em JavaScript usando os métodos push e shift ou métodos shift e pop do objeto de matriz. Embora essa seja uma maneira simples de implementar filas, é muito ineficiente para grandes filas - por causa dos métodos operarem em matrizes, os métodos shift e unshift movem todos os elementos da matriz toda vez que são chamados.

O Queue.js é uma implementação de fila simples e eficiente para JavaScript cuja função de desenfileiramento é executada em tempo constante amortizado. Como resultado, para filas maiores, pode ser significativamente mais rápido do que usar matrizes.


2
Com o link que você compartilhou, houve a funcionalidade de verificar os resultados do benchmark e não vejo ganhos de desempenho quando testados com o Google Chrome versão 59. O Queue.js é incosistente à sua velocidade, mas o Chrome era consistente com sua velocidade.
Shiljo Paulson

Também fiz uma demonstração com o queue.js, que, a função dequeue, na verdade, não remove o item da fila, então me pergunto se é suposto que seja assim que funciona? Nesse caso, como você pode recuperar a nova fila após desenfileirar o item anterior? codepen.io/adamchenwei/pen/VxgNrX?editors=0001
Ezeewei

parece que a desenfileiramento em queue.js também requer memória adicional, pois está clonando a matriz com fatia.
JATO

Além disso, a matriz subjacente está ficando cada vez maior a cada elemento adicionado. Mesmo que a implementação reduza o tamanho da matriz de tempos em tempos, o tamanho geral aumenta.
Philipp Mitterer

73

Matrizes.

Pilha:

var stack = [];

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

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

Fila:

var queue = [];

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

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

1
Array.prototype.pop não remove o valor da parte superior (primeiro elemento) da matriz. Remove o valor da parte inferior (último elemento) da matriz.
Michael Geller

21
@MichaelGeller O topo da pilha é o último elemento da matriz. Os métodos push e pop de matriz se comportam como uma pilha.
Mrdommyg 13/10/19

@mrdommyg Array.prototype.pop remove o último elemento da matriz (consulte developer.mozilla.org/en/docs/Web/JavaScript/Reference/… ). Por último, neste contexto, significa o elemento com o índice mais alto. Uma matriz em JS não tem nada a ver com uma pilha. Não é uma pilha apenas porque possui um método pop. Pop significa apenas "remover o último elemento e devolvê-lo". É claro que você pode imitar a funcionalidade de uma pilha com uma matriz, mas uma matriz ainda não é uma pilha por definição. Ainda é uma lista (um objeto "lista como" de acordo com o MDN).
Michael Geller

5
@ MichaelGeller O comportamento de uma pilha é "primeiro a entrar, último a sair". Se você implementá-lo usando uma matriz em JavaScript com seus métodos pushe pop, o problema será resolvido. Eu realmente não vejo o seu ponto aqui.
Rax Weber

2
@MichaelGeller Uma pilha é conceitual. Uma matriz JS é (entre outras coisas), por definição, uma pilha em virtude da implementação da semântica da pilha. Só porque ele também implementa a semântica de array não muda isso. Você pode usar uma matriz JS como uma pilha pronta para uso e, nesse contexto, o que você pressiona e abre é o elemento "top".
27717 Hans

32

Se você quiser criar suas próprias estruturas de dados, poderá criar suas próprias:

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 para fila:

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
Para evitar a necessidade de iterar sobre a coisa toda, a fim de acrescentar ao final, armazene uma referência à última via this.last = node;
Perkins

9
Nunca implemente nenhuma fila como essa, a menos que você tenha uma boa razão para isso ... embora possa parecer logicamente correto, as CPUs não operam de acordo com abstrações humanas. A iteração sobre uma estrutura de dados que possui ponteiros em todo o lugar resultará em falhas de cache na CPU, ao contrário de uma matriz seqüencial altamente eficiente. blog.davidecoppola.com/2014/05/… Os processadores odeiam ponteiros com uma paixão ardente - eles provavelmente são a causa número 1 de falhas no cache e precisam acessar a memória da RAM.
Centril 16/09/2015

1
esta é uma solução tentadora, mas não vejo os Nodecriadores sendo excluídos quando popping / desenfileiramento ... eles não ficam apenas ocupando memória demais até o navegador travar?
Cneuro

5
@cneuro Ao contrário do C ++, o JavaScript é uma linguagem de coleta de lixo. Ele tem uma deletepalavra - chave, mas isso só é útil para marcar uma propriedade de um objeto como não presente - o que é diferente de apenas atribuir undefinedà propriedade . O JavaScript também possui um newoperador, mas isso é usado apenas para definir thisum novo objeto vazio ao chamar uma função. Em C ++, você precisa emparelhar todos newcom a delete, mas não em JavaScript, porque o GC. Para parar de usar memória em JavaScript, pare de fazer referência ao objeto e ele será recuperado.
binki

Também não é necessário verificar se há excesso na pilha, definindo um tamanho máximo de pilha?
abelha.

16

Minha implementação Stacke QueueusoLinked 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

O deslocamento da matriz Javascript () é lento, especialmente quando há muitos elementos. Conheço duas maneiras de implementar a fila com complexidade O (1) amortizada.

O primeiro é usar buffer circular e duplicação de tabelas. Eu já implementei isso antes. Você pode ver meu código fonte aqui https://github.com/kevyuu/rapid-queue

A segunda maneira é usar duas pilhas. Este é o código para a fila com duas pilhas

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;}

Esta é uma comparação de desempenho usando jsPerf

CircularQueue.shift () vs Array.shift ()

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

Como você pode ver, é significativamente mais rápido com grandes conjuntos de dados


8

Existem várias maneiras pelas quais você pode implementar pilhas e filas em Javascript. A maioria das respostas acima são implementações bastante superficiais e eu tentaria implementar algo mais legível (usando os novos recursos de sintaxe do es6) e robusto.

Aqui está a implementação da pilha:

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;
  }
}

E é assim que você pode usar a pilha:

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 você deseja ver a descrição detalhada sobre esta implementação e como ela pode ser melhorada, leia aqui: http://jschap.com/data-structures-in-javascript-stack/

Aqui está o código para implementação da fila no 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
  }
}

Veja como você pode usar esta implementação:

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

Para seguir o tutorial completo de como essas estruturas de dados foram implementadas e como elas podem ser melhoradas, consulte a série 'Jogando com estruturas de dados em javascript' em jschap.com. Aqui estão os links para filas - http://jschap.com/playing-data-structures-javascript-queues/


7

Você pode usar sua própria classe de customização com base no conceito, aqui o trecho de código que você pode usar para fazer as coisas

/*
*   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 para verificar isso, use seu console e tente estas linhas, uma por uma.

>> 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
Voto negativo para uma convenção de nomenclatura: método que começa com um capital assumido como construtor.
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

Ou então, você pode usar duas matrizes para implementar a estrutura de dados da fila.

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

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

Se eu exibir os elementos agora, a saída será 3,2,1. Mas queremos uma estrutura FIFO para que você possa fazer o seguinte.

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
Esta é apenas funciona se você nunca pushdepois da primeira vez que vocêpop
jnnnnn

5

Aqui está uma implementação de fila bastante simples com dois objetivos:

  • Ao contrário de array.shift (), você sabe que esse método de remoção da fila leva tempo constante (O (1)).
  • Para melhorar a velocidade, essa abordagem usa muito menos alocações do que a abordagem de lista vinculada.

A implementação da pilha compartilha apenas o segundo objetivo.

// 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

A implementação da pilha é trivial, conforme explicado nas outras respostas.

No entanto, não encontrei respostas satisfatórias neste tópico para implementar uma fila em javascript, então criei as minhas.

Existem três tipos de soluções neste segmento:

  • Matrizes - A pior solução, usando array.shift()uma matriz grande, é muito ineficiente.
  • Listas vinculadas - É O (1), mas o uso de um objeto para cada elemento é um pouco excessivo, especialmente se houver muitos deles e forem pequenos, como armazenar números.
  • Matrizes de turno atrasado - consiste em associar um índice à matriz. Quando um elemento é desenfileirado, o índice avança. Quando o índice atinge o meio da matriz, ela é dividida em duas para remover a primeira metade.

Matrizes de turnos atrasados ​​são a solução mais satisfatória em minha mente, mas ainda armazenam tudo em um grande array contíguo que pode ser problemático, e o aplicativo cambaleia quando o array é fatiado.

Fiz uma implementação usando listas vinculadas de pequenas matrizes (no máximo 1000 elementos cada). As matrizes se comportam como matrizes de turno atrasado, exceto que nunca são fatiadas: quando todos os elementos da matriz são removidos, a matriz é simplesmente descartada.

O pacote está no npm com funcionalidade FIFO básica, acabei de enviar recentemente. O código é dividido em duas partes.

Aqui está a primeira 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;
}

E aqui está a Queueclasse principal :

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;
}

As anotações de tipo ( : X) podem ser facilmente removidas para obter o código javascript ES6.


4

Se você entende pilhas com as funções push () e pop (), a fila é apenas para realizar uma dessas operações no sentido oposto. Oposto de push () é não shift () e o oposto de pop () es shift (). Então:

//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

Uma palavra de aviso para aqueles que escrevem software crítico de desempenho. O .shift()método não é uma implementação de fila adequada. É O (n) em vez de O (1) e será lento para grandes filas.
Rudi Kershaw

3

Aqui está a versão da lista vinculada de uma fila que também inclui o último nó, conforme sugerido por @perkins e conforme mais apropriado.

// 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;
};

Na desenfileiramento, você deve retornar temp.data. Porque é isso que estava na fila.
não-um-robô

3

Se você estiver procurando pela implementação do ES6 OOP da estrutura de dados Stack and Queue com algumas operações básicas (com base em listas vinculadas), pode ser o seguinte:

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);
  }
}

A implementação do LinkedList usada para Stack e Queue nos exemplos acima pode ser encontrada no GitHub aqui .


2

Nenhuma matriz

//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;
    }

}

Como posso executar determinadas funções internas como push pop?
precisa

2

A estrutura Array regular em Javascript é uma pilha (primeiro a entrar, último a sair) e também pode ser usada como uma fila (primeiro a entrar, primeiro a sair), dependendo das chamadas feitas.

Verifique este link para ver como fazer uma matriz agir como uma fila:

Filas


2

Saudações,

Em Javascript, a implementação de pilhas e filas é a seguinte:

Pilha: Uma pilha é um contêiner de objetos que são inseridos e removidos de acordo com o princípio LIFO (last-in-first-out).

  • Push: O método adiciona um ou mais elementos ao final de uma matriz e retorna o novo comprimento da matriz.
  • Pop: O método remove o último elemento de uma matriz e retorna esse elemento.

Fila: Uma fila é um contêiner de objetos (uma coleção linear) que são inseridos e removidos de acordo com o princípio FIFO (primeiro a entrar, primeiro a sair).

  • Unshift: o método adiciona um ou mais elementos ao início de uma matriz.

  • Shift: o método remove o primeiro elemento de uma matriz.

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

Parece-me que a matriz incorporada é adequada para uma pilha. Se você deseja uma fila no TypeScript, aqui está uma implementação

/**
 * 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);
  }

}

E aqui está um Jestteste para isso

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();
});

Espero que alguém ache isso útil,

Felicidades,

Stu


0

Crie um par de classes que forneça os vários métodos que cada uma dessas estruturas de dados possui (push, pop, peek, etc). Agora implemente os métodos. Se você estiver familiarizado com os conceitos por trás da pilha / fila, isso deve ser bem direto. Você pode implementar a pilha com uma matriz e uma fila com uma lista vinculada, embora certamente existam outras maneiras de fazer isso. O Javascript facilitará isso, porque é de tipo fraco, para que você nem precise se preocupar com tipos genéricos, o que seria necessário se estivesse implementando em Java ou C #.


0

Aqui está minha implementação de pilhas.

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

você pode usar o WeakMaps para implementar a propriedade privada na classe ES6 e os benefícios das propriedades e métodos de String na linguagem JavaScript, como abaixo:

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

Construa uma fila usando duas pilhas.

O (1) para operações de enfileiramento e desenfileiramento.

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());
    }
  }
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.