Estrutura de Dados com JavaScript: Lista Encadeada

Listas encadeadas são estruturas de dados feitas de grupos de nós que juntos representam uma sequência. Você notará que a Fila e a Pilha foram criadas usando a ideia básica de uma lista encadeada. No entanto, eles têm regras especiais que os tornam diferentes em funcionalidade.

function ListaEncadeada() {
    let contador = 0;
    let head = null;

    this.GetCount = function(){
        return countador;
    }

} 

Nossa lista encadeada terá 6 métodos adicionais: DisplayAll (), DisplayAt (índice), AddFirst (dados), Add (dados, índice), RemoveFirst (), RemoveAt() .

DisplayAll():

Descrição:

O nome já diz tudo. Retorna um array com os dados ou, se vazio, retorna nulo.

this.DisplayAll = function() {
    // se está vazio
    if (head === null) {
        return null;
    } else {
        //senão, percorre a lista e a coloca em um array.
        let arr = new Array();
        let atual = head;

        for (let i = 0; i < contador; i++) {
            arr[i] = atual.dado;
            atual = atual.próximo;
        }
        return arr;
    }
}

DisplayAt():

Descrição:

Como o método PeekAt (indice) anterior da Fila, é exibido em um índice específico ou, fora dos limites, ele retorna null.

this.DisplayAt = function(indice) {
    // verifique se há valores fora dos limites
    if (indice > -1 && indice < contador) {
        let atual = head;
        let i = 0;

        // não fui eu, é da nczonline (veja fonte).
        // É uma maneira diferente de implementar o FOR que estamos usando
        // e eu queria que todos tivessem a chance de conhecê-lo.
        while (i++ < indice) {
            atual = atual.proximo;
        }

        return atual.dado;
    } else {
        return null;
    }
}

AddFirst():

Descrição:

Adiciona à frente da lista. Se você está se perguntando, frente é onde o índice é 0 e referenciado pelo cabeçalho.

this.AddFirst = function(dado) {
    // Cria um novo nó
    let node = {
        dado: dado,
        proximo: head
    };

    head = node;
    contador++;
}

Add()

Descrição:

Adiciona um item à lista na posição especificada.

this.Add = function(dado, indice) {
    // se o índice escolhido for 0, faça o método AddFirst (dado).
    if (indice === 0) {
        this.AddFirst(dado);
    }
    // verifique se há valores fora dos limites
    else if (indice > -1 && indice < contador) {
        let node = {
            dado: dado,
            proximo: null
        };

        let anterior;
        let atual = head;
        let i = 0;

        // encontre o local certo
        while (i++ < indice) {
            anterior = atual;
            atual = atual.proximo;
        }

        anterior.proximo = node;
        node.proximo = atual;

        contador++;
    } else {
        alert("fora de alcance");
    }
}

RemoveFirst()

Descrição:

Remove o primeiro item.

this.RemoveFirst = function() {
    // se não há itens na lista, retorna nulo
    if (head === null) {
        return null;
    } else {
        let out = head;
        head = head.proximo;

        if (contador > 0) {
            contador--;
        }

        return out.dado;
    }
}

RemoveAt()

Descrição:

Remove um item de um índice específico.

this.RemoveAt = function(indice) {
    if (indice === 0) {
        return this.RemoveFirst(indice);
    }
    // verifique se há valores fora dos limites
    else if (indice > -1 && indice < contador) {

        let atual = head;
        let anterior;
        let i = 0;

        // encontre a localização correta
        while (i++ < indice) {
            anterior = atual;
            atual = atual.proximo;
        }

        // pule o item para remover
        anterior.proximo = atual.proximo;

        // diminuir o comprimento
        contador--;
    } else {
        return null;
    }

    // retorna o valor
    return atual.dado;
}
  • DISPLAYALL():
  • DISPLAYAT(INDICE):
  • ADDFIRST(DADO):
  • ADD(DADO,INDICE):
  • REMOVEFIRST():
  • REMOVEAT(INDICE):

Gostou deste artigo? Comente abaixo!

Estrutura de Dados com JavaScript: Fila

Filas são coletâneas de dados que mantém os objetos em uma ordem determinada ao aplicar o algoritmo FIFO (First In First Out), ou seja, o primeiro a entrar é o primeiro a sair.

function Fila(){
    let contador = 0;

    // Ambos início e final da fila estão nulos (não possuem nenhum dado)
    let inicio = null;
    let final = null;

    // Retorna a quantidade de itens na fila.
    this.GetContador = function(){
        return contador;
    }
}

A nossa fila terá quatro métodos adicionais: enqueue(dado), dequeue(), peekAt() e displayAll().

Enqueue():

Descrição:

Adiciona um item no início da fila. O processo é o mesmo do método push() utilizado na pilha, mas foi alterado por causa do exercício.

this.Enqueue = function (dado){
    // Cria um nó com o dado
    let node = {
        dado: dado,
        // Os próximos pontos serão para valorizar de maneira linear
        // Se o início está vazio (null), não será um problema
        proximo: inicio
    };

    // Se é o primeiro item a ser inserido na lista
    // o início será o final
    if (inicio === null){
        tail = node;
    }

    // define o nó como o novo início
    inicio = node;

    //incrementa o contador
    contador++;
}

Dequeue()

Descrição:

Remove e retorna o último item inserido e armazenado que seria aquele no lado oposto da fila.

this.Dequeue = function(){
    // Se a fila está vazia, retorna null
    if (contador === 0){
        return;
    }else{
        let atual = inicio;
        let anterior = null;
    }

    // Enquanto houver um próximo, ele avançará a fila
    // A ideia é ter um atual no final e um anterior
    while (atual.proximo){
        anterior = atual;
        atual = atual.proximo;
    }

    // se há mais que 1 item, 
    // remove o final e decrementa o contador em 1
    if (contador > 1){
        // remove a referência ao último nó.
        anterior.proximo = null;

        // torna o nó anterior como final da lista
        final = anterior;
    }

    // Reseta a fila
    else{
        inicio = null;
        final = null;
    }

}

DisplayAll()

Descrição:

O nome já diz tudo. Ele funciona da mesma maneira que o método da pilha().

this.DisplayAll =  function(){
    // Se não há nada no início, nada será retornado
    if (inicio === null){
        return null;
    }else{
        let arr = new Array();
        let atual = inicio;

        for ( let i = 0; i < contador; i++){
            arr[i] = atual.dado;
            atual = atual.proximo;
        }
        return arr;
    }
}

PeekAt()

Descrição:

Segue a mesma ideia do peek(), mas qualquer item da fila pode ser buscado e exibido.

this.PeekAt = function (index){
    // Qualquer coisa menor que 0 e igual ou maior que a contagem não está na fila
    if (index > -1 && index < contador){
        let atual = inicio;

        // Navega pela fila para achar o item
        for (let i = 0; i < index; i++){
            atual = atual.proximo;
        }
        return atual.dado;
    }
    // Um index fora dos limites da fila foi escolhido
    else{
        return null;
    }
}
  • enqueue(dado)
  • dequeue()
  • displayAll()
  • peekAt(index)

Gostou deste artigo? Comente abaixo!

Estrutura de Dados com JavaScript: Pilha

Uma pilha é um tipo particular de dado em que as principais operações são a adição de um item (método push()) e remoção (método pop()). A pilha implementa um algoritmo LIFO (Last In First Out), que é uma estrutura onde o último elemento adicionado deve ser o primeiro a ser removido. Inicialmente, ela terá o seguinte código:

 

function pilha(){
    //cria uma variável que servirá 
     //para criação da pilha
    let topo = null; 
    let contador = 0;

    //Retorna o número de itens da fila
    this.GetContador = function(){
        return contador;
    }

    /* Métodos */
}

A nossa pilha terá quatro métodos adicionais: push(), pop(), peek() e displayAll(). Eles serão definidos dentro da função pilha() abaixo de this.GetContador. Vamos começar:

Push():

Descrição:

O método push() adiciona os dados especificados na pilha e o torna o nó do topo. Ele também aumenta a contagem de pilhas em 1.

this.Push = function (dado) {
    // Cria um nó que contém o dado e a referência para o próximo item
    let node = {
        dado: dado, 
        proximo: null
    };

    // Linka o nó atual para o topo da pilha
    // O próximo nó receberá o valor null como referência.
    node.proximo = topo;
        
    // Faz o nó atual ser o topo da pilha
    topo = node;

    // Incrementa o contador
    contador++;
}

Peek()

Descrição:

Exibe o item do topo da pilha. Retorna null se a pilha estiver vazia.

this.Peek = function(){
    // Se a lista estiver vazia, retornará null
    // senão, retornará o dado que estiver no nó topo.
    if (topo === null){
        return null;
    }else{
        return topo.dado;
    }
}

Pop()

Descrição:

Parece muito com o método peek(), com a diferença que o pop() remove o item que está no topo da pilha e diminui o contador em 1.

this.Pop = function(){
    // Se a lista estiver vazia, retornará null
    if(topo === null){
        return null;
    }else{
        // Atribui o topo a uma variável temporária
        let out = topo;

        // Atribui o topo para o próximo elemento da pilha
        topo = topo.proximo;

        // Se existir itens na pilha, decrementa o contador
        if (contador > 0){
            contador--;
        }

        // Retorna o valor que foi removido da pilha
        return out.dado;
    }
}

displayAll()

Descrição:

Exibe todos os dados da pilha como um vetor. Exibi-lo como um vetor foi minha escolha, pois não tinha certeza sobre como iria exibi-lo (por exemplo: console.log; document.write etc.).

this.DisplayAll = function(){
    // Se a lista estiver vazia, retornará null
    if (topo === null){
        return null;
    }else{
        // Instancia um vetor
        let arr = new Array();
        // Cria um nó que irá percorrer a pilha
        let noAtual = topo;

        // Percorre a pilha até alcançar o item mais abaixo
        for (let i = 0; i < contador; i++){
            // Atribui os dados ao vetor
            arr[i] = noAtual.dado;
            // Avança para a próxima posição da pilha
            noAtual = noAtual.proximo;
        }

        // Retorna o vetor
        return arr;
    }
}

Métodos utilizados na estrutura do tipo PILHA:

  • push(dado)
  • peek()
  • pop()
  • displayAll()

Gostou deste artigo? Comente abaixo!

Criando a classe pilha com JavaScript

Neste post estarei fazendo uma implementação simples da estrutura de dados conhecida como Pilha utilizando o JavaScript. Apesar da lista JavaScript ser totalmente capaz de simular a pilha, fila, lista, etc… a ideia é focar na teoria e criar do zero uma pilha de nós (nodes) como se a funcionalidade não estivesse disponível.

Como funciona a pilha?

A pilha é um tipo de estrutura de dados que funciona no formato que o último item que foi inserido será o primeiro a ser removido da estrutura (Lifo – Last in, First out). Então quando você adicionar 3 números e quiser remove-los, eles serão removidos na ordem inversa que foram adicionados (terceiro – segundo – primeiro).

Considerações

Algumas considerações na nossa implementação para que não ocorra confusão:

  • A classe do JavaScript ainda não permite declarar propriedades como privadas, por isso usarei _ na frente do nome das propriedades ao qual NÂO deveríamos estar acessando externamente.
  •  Esta é uma implementação para uso acadêmico. Por favor utilize a lista do JavaScript para trabalhar com a pilha em produção (new Array ou []).
  • Alguns trechos de código poderiam ser resumidos em uma única linha, mas foram mantidos quebrados para auxiliar aqueles que estão aprendendo.

Implementação:

Classe e Construtor

Beleza, então vamos começar. A primeira coisa que precisamos é criar a classe e o construtor dela conforme o código abaixo. Para o nome da classe usaremos o termo em português, mas para o resto iremos utilizar os termos em Inglês pois parece ser o padrão mais utilizado por livros e cursos.

class Pilha {
  constructor() {
    this._top = null;
    this._count = 0;
  }

  //Continuação do código

Como você pode ver, teremos apenas duas variáveis de controle, _top que fará referencia para o topo da pilha e _count que controlará quantos itens a pilha possuí.

 

GetCount()

O método GetCount é o mais simples de todos. Ele apenas irá retornar a quantidade de itens na pilha.

GetCount = function () {
  return this._count;
};

 

Peek()

Exibe o item no topo da pilha ou null caso ela esteja vazia.

Peek = function () {
  if (this._top) {
    return this._top.data;
  }
  return null;
};

 

Push(item)

O método Push (empurrar) é a forma como adicionaremos itens a pilha. Pelo fato de ser uma linguagem não tipada, poderemos adicionar qualquer valor a pilha que ela o aceitará.

Push = function (data) {
  let node = {
    data: data,
    next: null
  };
  node.next = this._top;
  this._top = node;
  this._count++;
};

Como você pode ver, o método cria um objeto chamado node (nó) que é um objeto JS e terá 2 propriedades, o data (dados em inglês) para o valor e next (próximo) para referência o item anterior. Após isso definimos este novo valor como sendo o do topo e referenciamos o antigo topo no next.

Isto é feito desta forma pois para a pilha, é importante termos um controle de quem está no topo. Os outros itens serão manipulados apenas quando chegar a vez deles.

 

Pop()

O Método Pop (tirar) funciona da forma oposta ao Push, ele remove o item que está no topo da fila.

Pop = function () {
  if (this._top) {
    let out = this._top;
    this._top = this._top.next;
    if (this._count > 0) {
      this._count--;
    }
    return out.data;
  }
  return null;
};

Como você pode ver o código acima faz o seguinte: Confere se existe algum item no topo da fila para poder remove-lo, transforma o next em topo, reduz a contagem em 1 e retorna o item removido ou null caso esteja vazio.

 

DisplayAll()

Este método exibe todos os itens da pilha, do topo ao fundo, no formato de um vetor JavaScript. Caso a pilha esteja vazia, retorna null

DisplayAll = function () {
  if (this._top) {
    let arr = new Array();
    let current = this._top;
    for (let i = 0; i < this._count; i++) {
      arr[i] = current.data;
      current = current.next;
    }
    return arr;
  }

  return null;
};

Apesar deste código ter um pouco mais de lógica que os métodos anteriores, ele ainda é fácil de entender. Ele testa se o _top não está vazio e se verdadeiro, percorrerá a pilha copiando o valor armazenado dentro de cada nó para dentro do vetor.


Executando o código

Após criar a classe, um teste simples ajudará a verificar que todos os métodos estão fazendo o que deveriam

let pilha = new Pilha();

console.log(`Contagem: ${pilha.GetCount()}`);

pilha.Push(4);
console.log(`Peek: ${pilha.Peek()}`);
console.log(`Contagem: ${pilha.GetCount()}`);

pilha.Push(22);

console.log(`Contagem: ${pilha.GetCount()}`);

console.log(`Pop: ${pilha.Pop()}`);
console.log(`Pop: ${pilha.Pop()}`);
console.log(`Pop: ${pilha.Pop()}`);

console.log(`Contagem: ${pilha.GetCount()}`);

pilha.Push(1);
pilha.Push(-2);
pilha.Push(100);
pilha.Push(350);

console.log(`Todos: ${pilha.DisplayAll()}`);

Pilhas e Filas (Estrutura de dados)

[download id=”589″]

Neste artigo estarei explicando o funcionamento das estruturas de dados conhecidas como Pilha e Fila. O código fonte JavaScript será deixado disponível e uma breve explicação junto com o uso serão dados para cada uma delas.

Pilha

Conceito Básico

A pilha é uma estrutura de dados básica que fornece a lógica conhecida por LIFO(Last In, First out). Isso significa que o ultimo dado adicionado a estrutura será o primeiro removido dela e por isso foca a entrada e saída de dados na mesma ponta do vetor/lista.

Na prática, a pilha como um controle para serviços que dependem da conclusão do ultimo recurso ativado antes de prosseguirem. Exemplos de rotinas que utilizam essa lógica são o “desfazer” do Word e o gerenciamento da execução de funções (de programação), que causa o conhecido erro de stackoverflow.

Código Fonte

O código fonte abaixo não vai usar o vetor do JavaScript simplesmente para podermos ver em mais detalhes o funcionamento desta estrutura de dados. não será uitlizado um vetor, mas sim nós (nodes) que se conectam uns aos outros.

function Pilha() {
    var topo = null;
    var quantidade = 0;

    //Retorna o número de itens na Pilha
    this.GetCount = function () {
        return quantidade;
    }
    //Push: Adiciona itens ao topo da pilha
    this.Push = function (dados) {
        var node = {
            dados: dados,
            proximo: null
        };

        node.proximo = topo;
        topo = node;

        quantidade++;
    }
    //Pop: Remove itens do topo da pilha
    this.Pop = function () {
        if (topo === null) {
            return null;
        } else {
            var removido = topo;
            topo = topo.proximo;

            if (quantidade > 0) {
                quantidade--;
            }

            return removido.dados;
        }
    }
    //Exibe o Item do topo da pilha
    this.VerTopo = function () {
        if (topo === null) {
            return null;
        } else {
            return topo.dados;
        }
    }
    //Retorna um vetor com todos iitens da Pilha
    this.VerTodos = function () {
        if (topo === null) {
            return null;
        } else {
            var arr = new Array();
            var current = topo;

            for (var i = 0; i < quantidade; i++) {
                arr[i] = current.dados;
                current = current.proximo;
            }

            return arr;
        }
    }
}

Fila

Conceito Básico

Fila é um tipo de estrutura de dados com um controle definido pela lógica FIFO (do inglês first in, last out). Esse controle quer dizer que os dados contidos nela são podem entrar apenas por uma ponta e deverão sair pela outra. Com isso, garante-se que o primeiro dado que entrou será o primeiro a sair da fila.

A fila é uma estrutura de dados muito útil quando se possui um serviço ao qual o sistema recebe alimentação de diversas fontes, mas precisa manter uma ordem do “primeiro que chegou será o primeiro servido”. Um exemplo simples é o sistema que administra diversos computadores ligados a uma única impressora.

Código Fonte

O código fonte abaixo não vai usar o vetor do JavaScript simplesmente para podermos ver em mais detalhes o funcionamento desta estrutura de dados. Não será utilizado um vetor como forma de controle mas sim nós contectados uns aos outros, irei também fazer com que o ato de adicionar o faça no começo da fila e o de remover será na outra ponta.

function Fila() {
    var quantidade = 0;
    var primeiro = null;
    var ultimo = null;

    //Retorna a quantidade na fila
    this.GetQuantidade = function () {
        return quantidade;
    }
    //adiciona um item a fila
    this.Adicionar = function (data) {
        var node = {
            data: data,
            prox: primeiro
        };

        if (primeiro === null) {
            ultimo = node;
        }

        primeiro = node;

        quantidade++;
    }
    //Remove um item da fila
    this.Remover = function () {
        //se a fila estiver vaiza, retorna nulo
        if (ultimo === null) {
            return null;
        }
        else {
            //senão percorre a fila até o ultimo item para removelo e ajusta a lista
            var current = primeiro;
            var previous = null;

            while (current.prox) {
                previous = current;
                current = current.prox;
            }

            if (quantidade > 1) {
                previous.prox = null;

                ultimo = previous;
            }
            //zera/reseta a fila
            else {
                primeiro = null;
                ultimo = null;
            }
            quantidade--;
        }
        //Exibe todos os itens da fila
        this.ExibirTodos = function () {
            if (primeiro === null) {
                return null;
            } else {
                var arr = new Array();
                var current = primeiro;

                for (var i = 0; i < quantidade; i++) {
                    arr[i] = current.data;
                    current = current.prox;
                }

                return arr;
            }
        }
    }
}