Uma pilha é uma estrutura de dados linear que segue o princípio "Last In, First Out" (LIFO), ou seja, o último elemento inserido é o primeiro a ser removido. As operações em pilhas são restritas ao topo, sendo impossível acessar ou remover elementos do meio ou base diretamente.
As operações fundamentais de uma pilha incluem:
- push - Insere um novo elemento no topo da pilha
- peek - Retorna o elemento do topo sem removê-lo
- pop - Remove e retorna o elemento do topo
Uma pilha pode ser implementada utilizando tanto arrays quanto listas encadeadas. A implementação com arrays oferece acesso mais rápido aos elementos, mas possui tamanho fixo. Já a implementação com listas encadeadas permite crescimento dinâmico, mas tem maior sobrecarga de memória.
Implementação com Array
A seguir, uma implementação de pilha utilizando uma estrutura de array:
public class Pilha {
private Object[] elementos;
private int capacidade;
private int topo;
public Pilha(int capacidade) {
this.capacidade = capacidade;
this.elementos = new Object[capacidade];
this.topo = -1;
}
public void empilhar(Object item) {
if (estaCheia()) {
throw new IllegalStateException("A pilha está cheia");
}
elementos[++topo] = item;
}
public Object desempilhar() {
if (estaVazia()) {
throw new IllegalStateException("A pilha está vazia");
}
return elementos[topo--];
}
public Object topo() {
if (estaVazia()) {
throw new IllegalStateException("A pilha está vazia");
}
return elementos[topo];
}
public boolean estaVazia() {
return topo == -1;
}
public boolean estaCheia() {
return topo == capacidade - 1;
}
public int tamanho() {
return topo + 1;
}
}
Testando a Implementação com Array
public static void main(String[] args) {
Pilha pilha = new Pilha(5);
pilha.empilhar("Primeiro");
pilha.empilhar("Segundo");
pilha.empilhar("Terceiro");
pilha.empilhar(100);
System.out.println("Tamanho atual da pilha: " + pilha.tamanho());
Object elementoTopo = pilha.topo();
System.out.println("Elemento no topo: " + elementoTopo);
pilha.desempilhar();
System.out.println("Elemento removido do topo");
System.out.println("Novo tamanho da pilha: " + pilha.tamanho());
}
Resultado esperado:
Tamanho atual da pilha: 4
Elemento no topo: 100
Elemento removido do topo
Novo tamanho da pilha: 3
Implementação com Lista Encadeada
Agora, uma alternativa de implementação utilizando lista encadeada simples:
public class PilhaEncadeada {
private No cabeca;
private int tamanho;
private static class No {
Object dado;
No proximo;
No(Object dado) {
this.dado = dado;
this.proximo = null;
}
}
public PilhaEncadeada() {
this.cabeca = null;
this.tamanho = 0;
}
public void empilhar(Object item) {
No novoNo = new No(item);
novoNo.proximo = cabeca;
cabeca = novoNo;
tamanho++;
}
public Object desempilhar() {
if (estaVazia()) {
throw new IllegalStateException("A pilha está vazia");
}
Object dado = cabeca.dado;
cabeca = cabeca.proximo;
tamanho--;
return dado;
}
public Object topo() {
if (estaVazia()) {
throw new IllegalStateException("A pilha está vazia");
}
return cabeca.dado;
}
public boolean estaVazia() {
return cabeca == null;
}
public int tamanho() {
return tamanho;
}
}
Tesatndo a Implementação com Lista Encadeada
public static void main(String[] args) {
PilhaEncadeada pilha = new PilhaEncadeada();
pilha.empilhar(10);
pilha.empilhar(20);
pilha.empilhar(30);
pilha.empilhar(40);
System.out.println("Tamanho atual: " + pilha.tamanho());
Object elementoTopo = pilha.topo();
System.out.println("Elemento no topo: " + elementoTopo);
pilha.desempilhar();
System.out.println("Elemento removido");
System.out.println("Novo tamanho: " + pilha.tamanho());
}
Resultado esperado:
Tamanho atual: 4
Elemento no topo: 40
Elemento removido
Novo tamanho: 3