Pilhas Profa. Nádia Félix Definição • Uma pilha é uma coleção de objetos que são inseridos e retirados de acordo com o princípio de que o último que entra é o primeiro que sai (LIFO – LAST-IN, FIRST-OUT). • É possível inserir objetos em uma pilha a qualquer momento, mas somente o objeto inserido mais recentemente (o último que entrou) pode ser removido a qualquer momento. Definição • O nome “pilha” deriva-se da metáfora de uma pilha de pratos em uma cantina. – Retira-se o prato do topo da pilha (pop); – Coloca-se o prato na pilha (push) • As pilhas são uma estrutura de dados fundamental: elas são usadas em muitas aplicações, como por exemplo: – Navegadores para a Internet armazenam os endereços mais recentemente visitados em uma pilha. Cada vez que o navegador visita um novo site, o endereço do site é armazenado na pilha de endereços. O navegador permite que o usuário retorne o site previamente visitados (“pop”) usando o botão “back”. – Editores de texto geralmente oferecem um mecanismo de reversão de operações (“undo”) que cancela operações recentes e reverte um documento a estados anteriores. A operação de reversão é implementada mantendo-se as alterações no texto em uma pilha. O tipo abstrato de dados Pilha • Pilhas são as mais simples de todas estruturas de dados, apesar de estar entre uma das mais importantes. O tipo abstrato de dados Pilha • Formalmente, uma pilha S é um tipo abstrato de dados (TAD) que suporta os dois métodos que seguem: push(e): insere o objeto e no topo da pilha. pop( ): remove o elemento no topo da pilha e o retorna; ocorre um erro se a pilha estiver vazia. • Adicionalmente, podem-se definir os seguintes métodos: size ( ): retorna o número de elementos na pilha. isEmpty( ): retorna um booleano indicando se a pilha está vazia. top( ): retorna o elemento no topo da pilha, sem retirá-lo; ocorre um erro se a pilha estiver vazia. Exemplo: A tabela a seguir mostra uma série de operações de pilha e seus efeitos sobre uma pilha S de inteiros, inicialmente vazia Operação Saída Conteúdo da pilha push(5) - (5) push(3) - (5,3) pop() 3 (5) push(7) - (5,7) pop() 7 (5) top() 5 (5) pop() 5 () pop() “error” () isEmpty() true () push(9) - (9) push(7) - (9,7) push(3) - (9,7,3) push(5) - (9,7,3,5) size() 4 (9,7,3,5) pop() 5 (9,7,3) push(8) - (9,7,3,8) Pilha- em Java • A estrutura de dados pilha é uma classe “embutida” no pacote java.util.Stack • Inclui entre outros, os métodos push(), pop(), peek() (equivalente ao método top()), size() e empty() (equivalente a isEmpty()). • Os métodos pop() e peek() lançam a exceção EmptyStackException se a pilha estiver vazia quando eles forem chamados. • Embora seja conveniente usar a classe java.util.Stack, é instrutivo aprender como projetar e implementar uma pilha desde o início. Uma interface para Pilhas em Java • Implementar um tipo abstrato de dados em Java envolve dois passos: – Definição de uma Application Programming Interface (API), ou simplesmente interface que descreve os nomes dos métodos que o TAD suporta e como eles são declarados e usados. – Definir exceções para qualquer condição de erro que possa ocorrer. • Por exemplo: A condição de erro que ocorre quando se chama os métodos pop() ou top() sobre uma pilha vazia é sinalizada pelo lançamento de uma exceção do tipo EmptyStackException Definindo Exceção • A condição de erro que ocorre quando se chama os métodos pop( ) ou top( ) sobre uma pilha vazia é sinalizada pelo lançamento de uma exceção do tipo EmptyStackException. public class EmptyStackException extends RuntimeException{ public EmptyStackException(String err){ super(err); } } Definindo a Interface da Pilha public interface interfStack<E> { /** * Retorna o número de elementos da pilha * @return número de elementos na pilha. */ public int size(); /** * Indica quando a pilha está vazia * @return true se a pilha é vazia, false em caso contrário */ public boolean isEmpty(); /** * Inspeciona o elemento no topo da pilha * @return o elemento do topo da pilha. * @exception EmptyStackException se a pilha estiver vazia. */ public E top() throws EmptyStackException; /** * Insere um elemento no topo da pilha. * @param elemento a ser inserido. */ public void push(E element); /** * Remove o elemento do topo da pilha. * @return elemento a ser removido. * @exception EmptyStackException se a * pilha estiver vazia. */ public E pop() throws EmptyStackException; } Uma Implementação baseada em Arranjos • A pilha desta implementação necessita: – Um Arranjo S de N elementos; – Uma variável t, que fornece o índice do elemento topo no arranjo S; • t = -1, pilha vazia. … S 0 1 2 t N-1 – Uma nova exceção (específica para esta implementação) chamada FullStackException, que sinalizará uma condição de erro ao se tentar inserir um novo elemento em um arranjo cheio. – Observação: t pode ser usada para calculo do size t+1 Classe FullStackException public class FullStackException extends RuntimeException { public FullStackException(String err) { super(err); } } Implementação de uma pilha através de um arranjo de tamanho fixo, N Algoritmo size() return t + 1 Algorithm pop() if isEmpty() then throw EmptyStackException else tt1 return S[t + 1] -São adicionados elementos da esquerda para direita -Uma variável controla o índice do elemento do topo … S 0 1 2 t Implementação de uma pilha através de um arranjo de tamanho fixo, N -O array que armazena os objetos pode ficar cheio. -Uma operação push poderá lançar uma exceção FullStackException. Algorithm push(o) if t = S.length 1 then throw FullStackException else tt+1 S[t] o … S 0 1 2 t Implementação da interface interfStack public interface interfStack<E> { /** * Retorna o número de elementos da pilha * @return número de elementos na pilha. */ public int size(); /** * Indica quando a pilha está vazia * @return true se a pilha é vazia, false em caso contrário */ public boolean isEmpty(); /** * Inspeciona o elemento no topo da pilha * @return o elemento do topo da pilha. * @exception EmptyStackException se a pilha estiver vazia. */ public E top() throws EmptyStackException; /** * Insere um elemento no topo da pilha. * @param elemento a ser inserido. */ public void push(E element); /** * Remove o elemento do topo da pilha. * @return elemento a ser removido. * @exception EmptyStackException se a * pilha estiver vazia. */ public E pop() throws EmptyStackException; } Implementação da interface da Pilha public class ArrayStack<E> implements interfStack<E>{ protected int capacidade; //capacidade real do arranjo da pilha public static final int CAPACIDADE = 1000; //capacidade padrão do arranjo protected E S[]; //Arranjo genérico usado para implementar a pilha protected int topo = -1; //índice para o topo da pilha public ArrayStack(){ this(CAPACIDADE); //capacidade padrão } public ArrayStack(int cap){ capacidade = cap; S = (E[])new Object[capacidade]; } public int size(){ return (topo + 1); } public boolean isEmpty(){ return (topo<0); } public void push(E elemento) throws FullStackException { if(size()==capacidade){ throw new FullStackException("Pilha está Cheia!"); } S[++topo] = elemento; } public E top() throws EmptyStackException{ if(isEmpty()) throw new EmptyStackException("Pilha está Vazia!"); return S[topo]; } public E pop() throws EmptyStackException{ E elemento; if(isEmpty()) throw new EmptyStackException("Pilha está Vazia!“); elemento = S[topo]; S[topo--]=null; return elemento; } public String toString(){ String s; s = " ["; if(size()>0) s+=S[0]; if(size()>1) for(int i = 1; i<=size()-1;i++){ s+= ", "+S[i]; } return s + "]"; } public void status(String op, Object elemento){ //imprime esta operação System.out.print("--------> "+op); //o que foi retornado System.out.println(" , retorna "+elemento); System.out.print("resultado: tamanho = " + size()+ " , Pilha Vazia? "+isEmpty()); //conteúdo da pilha System.out.println(", pilha: "+this); } }