Você está na página 1de 10

Pilhas "O pessimista queixa-se do vento, o otimista espera que ele mude e o realista aj usta as velas. " 6.

1 - Introduo Um determinado produto composto por diversas peas (digamos p1, p2, ...,pn). O pro cesso de montagem deste produto automtico (executado por uma mquina) e exige que a s peas sejam colocadas em uma ordem especfica (primeiro a p1, depois a p2, depois a p3 e assim por diante). As peas so empilhadas na ordem adequada e a mquina de mon tagem vai retirando pea por pea do topo desta pilha para poder montar o produto fi nal. A mesma mquina que faz a montagem capaz de trocar uma pea quebrada de um produto j montado. O que a mquina faz desmontar o produto at chegar na pea defeituosa, troc-la e ento depois recolocar as peas que foram retiradas. Isso tambm feito com o uso da pilha de peas. Veja a seguir o algoritmo que a mquina montadora implementa para f azer a manuteno de um produto com defeito. Retirar e empilhar pea por pea do produto at chegar na pea defeituosa. Retirar a pea defeituosa Colocar uma pea nova sem defeitos Desempilhar e montar pea por pea do topo da pilha at a pilha ficar vazia. De alguma forma uma pea precisa ser representada em nosso programa. Como estamos usando orientao a objetos as peas sero representadas por objetos. Uma classe Java se r criada somente para modelar as peas, algo similar ao cdigo a seguir: public class Peca { private String nome; public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } } Com a classe Peca, j possvel criar objetos para representar as peas que a mquina mon tadora utiliza. Porm, o sistema deve definir como guardar estes objetos, ou seja, ele precisa escolher uma estrutura de dados. Esta estrutura de dados deve mante r os dados seguindo alguma lgica e deve fornecer algumas operaes para a manipulao des tes e outras operaes para informar sobre seu prprio estado. 6.2 - Soluo do problemas das Peas Para implementar o algoritmo de manuteno do carro, necessrio criar uma estrutura de dados que se comporte como a pilha de peas. Vamos chamar esta estrutura de dados de Pilha. Primeiro, definimos a interface da Pilha (conjunto de operaes que queremos utiliza r em uma Pilha). Insere uma pea (coloca uma pea no topo da Pilha). Remove uma pea (retira a pea que est no topo da Pilha). Informa se a Pilha est vazia. Podemos criar uma classe Pilha para implementar esta estrutura de dados. Os mtodo s pblicos desta classe sero a implementao das operaes.

public class Pilha { public void insere(Peca peca) { // implementao } public Peca remove() { // implementao } public boolean vazia() { // implementao } } O primeiro fato importante que devemos observar que uma vez que a interface da P ilha foi definida, j saberamos usar a classe Pilha. Vamos criar uma classe de test e bem simples para exemplificar o uso de uma Pilha. public class Teste { public static void main(String[] args) { Pilha pilha = new Pilha(); Peca pecaInsere = new Peca(); pilha.insere(pecaInsere); Peca pecaRemove = pilha.remove(); if (pilha.vazia()) { System.out.println("A pilha est vazia"); } } } O segundo fato importante que a estrutura que queremos aqui muito similar as Lis tas que vimos anteriormente. A semelhana fundamental entre as Listas e as Pilhas que ambas devem armazenar os elementos de maneira sequencial. Este fato o ponto chave deste captulo. Qual a diferena entre uma Lista e uma Pilha? A diferena est nas operaes destas duas e struturas de dados. As operaes de uma Pilha so mais restritas do que as de uma List a. Por exemplo, voc pode adicionar ou remover um elemento em qualquer posio de uma Lista mas em uma Pilha voc s pode adicionar ou remover do topo. Ento, uma Lista uma estrutura mais poderosa e mais genrica do que uma Pilha. A Pil ha possui apenas um subconjunto de operaes da Lista. Ento o interessante que para i mplementar uma Pilha podemos usar uma Lista. Isso mesmo! Vamos criar restries sobr e as operaes da Lista e obteremos uma Pilha. Ns implementamos dois tipos de Listas: Vetores e Listas Ligadas. Vimos, tambm que, na biblioteca do Java, h implementaes prontas para estes dois tipos de Listas. Nes te captulo, vamos utilizar a classe LinkedList para armazenar as peas que sero guar dadas na Pilha. public class Pilha { private List<Peca> pecas = new LinkedList<Peca>(); } Dentro de nossa Pilha teremos uma LinkedList encapsulada, que vai simplificar ba stante o nosso trabalho: delegaremos uma srie de operaes para essa Lista Ligada, po

rm sempre pensando nas diferenas essenciais entre uma Pilha e uma Lista. Devemos ter um getPecas() que devolve uma referncia para essa nossa LinkedList? N esse caso a resposta no, pois estaramos expondo detalhes de nossa implementao, e o u surio dessa classe poderia mexer no funcionamento interno da nossa pilha, desresp eitando as regras de sua interface. sempre uma boa prtica expor o mnimo possvel do funcionamento interno de uma classe, gera um menor acoplamento entre as classes. Voc no est nessa pgina a toa Voc chegou aqui porque a Caelum referncia nacional em cursos de Java, Ruby, Agile, Mobile, Web e .NET. Faa curso com quem escreveu essa apostila. Consulte as vantagens do curso Algoritmos e Estruturas de Dados com Java. 6.3 - Operaes em pilhas: Inserir uma pea As peas so sempre inseridas no topo da Pilha. Ainda no definimos onde fica o topo d a Pilha. Como estamos utilizando uma Lista para guardar os elementos ento o topo da Pilha poderia ser tanto o comeo ou o fim da Lista. Aqui escolheremos o fim da Lista. Ento, inserir na Pilha simplesmente adicionar no fim da Lista. public class Pilha { private List<Peca> pecas = new LinkedList<Peca>(); public void insere(Peca peca) { this.pecas.add(peca); } } Recordando que o mtodo add(Object) adiciona no fim da Lista. 6.4 - Operaes em pilhas: Remover uma pea A remoo tambm bem simples, basta retirar o ltimo elemento da Lista. public class Pilha { private List<Peca> pecas = new LinkedList<Peca>(); ... public Peca remove() { return this.pecas.remove(this.pecas.size() - 1); } } bom observar que se o mtodo remove() for usado com a Pilha vazia ento uma exceo ser l anada pois o mtodo remove(int) da List lana IndexOutOfBoundsException quando no exis tir elemento para remover. 6.5 - Operaes em pilhas: Informar se a pilha est vazia Para implementar esta operao basta verificar se o tamanho da Lista zero. public class Pilha { private List<Peca> pecas = new LinkedList<Peca>(); ... public boolean vazia() {

return this.pecas.size() == 0; } } Na classe LinkedList existe tambm o mtodo isEmpty() que poderia ter sido usado aqu i mais convenientemente. Seus livros de tecnologia parecem do sculo passado? Conhea a Casa do Cdigo, uma nova editora, com em ebooks (PDF, epub, mobi), preos imbatveis Com a curadoria da Caelum e excelentes autores, ros de tecnologia no Brasil. Conhea os ttulos autores de destaque no mercado, foco e assuntos atuais. uma abordagem diferente para liv e a nova proposta, voc vai gostar.

Casa do Cdigo, livros para o programador. 6.6 - Generalizao Nossa Pilha s funciona para guardar objetos da classe Peca. Vamos generalizar a P ilha para poder armazenar qualquer tipo de objeto. Isso ser feito utilizando a cl asse Object da qual todas as classes derivam direta ou indiretamente. Criaremos uma LinkedList de Object em vez de uma LinkedList de Peca. public class Pilha { private List<Object> objetos = new LinkedList<Object>(); public void insere(Object objeto) { this.objetos.add(objeto); } public Object remove() { return this.objetos.remove(this.objetos.size() - 1); } public boolean vazia() { return this.objetos.size() == 0; } } Agora, podemos guardar qualquer tipo de objeto na Pilha. Isso uma grande vantage m pois a classe Pilha poder ser reaproveitada em diversas ocasies. Mas, h uma desva ntagem, quando removemos um elemento da Pilha no podemos garantir qual o tipo de objeto que vir. No Java 5, poderamos usar Generics para solucionar este problema. A nossa classe Pilha poderia ser uma classe parametrizada. Na criao de um objeto de uma classe pa rametrizada possvel dizer com qual tipo de objeto que queremos trabalhar. Algo deste tipo: Pilha de Peas pilha = new Pilha de Peas(); Traduzindo este cdigo para Java 5 de verdade, ficaria assim: Pilha<Peca> pilha = new Pilha<Peca>(); S que para utilizar o recurso do Generics devemos parametrizar a classe Pilha. public class Pilha<T> { private LinkedList<T> objetos = new LinkedList<T>(); public void insere(T t) { this.objetos.add(t);

} public T remove() { return this.objetos.remove(this.objetos.size() - 1); } public boolean vazia() { return this.objetos.size() == 0; } } Poderamos tambm adicionar outros mtodo provavelmente teis a manipulao de uma pilha, co mo saber o tamanho da pilha, espiar um elemento em determinada posio, entre outros . Vamos testar a classe Pilha que usa Generics. public class Teste { public static void main(String[] args) { Pilha<Peca> pilha = new Pilha<Peca>(); Peca peca = new Peca(); pilha.insere(peca); Peca pecaRemove = pilha.remove(); if (pilha.vazia()) { System.out.println("A pilha est vazia"); } Pilha<String> pilha2 = new Pilha<String>(); pilha2.insere("Adalberto"); pilha2.insere("Maria"); String maria = pilha2.remove(); String adalberto = pilha2.remove(); System.out.println(maria); System.out.println(adalberto); } } Neste exemplo, criamos duas Pilhas. A primeira vai armazenar s objetos do tipo Pe ca e a segunda s String. Se voc tentar adicionar um tipo de objeto que no correspon de ao que as Pilhas esto guardando ento um erro de compilao ser gerado para evitar qu e o programador cometa um erro lgico. 6.7 - API do Java Na biblioteca do Java existe uma classe que implementa a estrutura de dados que foi vista neste captulo, esta classe chama-se Stack e ser testada pelo cdigo abaixo . public class Teste { public static void main(String[] args) { Stack pilha = new Stack(); Peca pecaInsere = new Peca(); pilha.push(pecaInsere); Peca pecaRemove = (Peca)pilha.pop();

if(pilha.isEmpty()){ System.out.println("A pilha est vazia"); } } } Para evitar fazer casting de objetos, podemos utilizar o recurso de Generics aqu i tambm. public class Teste { public static void main(String[] args) { Stack<Peca> pilha = new Stack<Peca>(); Peca pecaInsere = new Peca(); pilha.push(pecaInsere); Peca pecaRemove = pilha.pop(); if (pilha.isEmpty()) { System.out.println("A pilha est vazia"); } } } 6.8 - Escapando do Labirinto Ao percorrer um labirinto para fugir do Minotauro, existe um algoritmo bastante simples: voc sempre escolhe o caminho mais a direita em toda oportunidade que apa recer a separao do caminho atual em dois ou mais. Caso caia em um beco sem sada, deve voltar at o ltimo ponto em que optou pelo camin ho mais a direita e mudar sua deciso: agora voc deve tentar o caminho mais a direi ta porm excluindo o que foi anteriormente selecionado (e que causou a chegada a u m beco sem sada). Se voc no tiver mais nenhuma opo, deve voltar mais ainda pelo camin ho j percorrido at encontrar outro ponto em que voc teve a opo de escolha. Esse proce sso de guardar o caminho e escolhas j feitos para tomar outra deciso conhecido com o backtracking. Para implementar esse algoritmo voc deve se lembrar do caminho percorrido e, alm d isso, em cada posio (x, y) em que houve opo de escolha deve tambm lembrar qual foi a l tima escolha feita, para poder muda-la quando voc voltar o caminho (backtrack). Uma soluo utilizar uma Pilha que armazene cada (x,y) onde uma deciso foi tomada, e tambm guardar um inteiro opcao que represente qual das opes foi escolhida no atual caminho: se escolhemos o mais da direita, guardamos 1, se j precisamos voltar uma vez e escolhemos o segundo mais da direita, guardamos 2, etc... Assim quando vo ltarmos a este ponto e precisarmos mudar de deciso, basta incrementar esse nmero. Caso no haja mais caminhos a percorrer por esse lado (isso , se opcao == totalDeOp coes daquele ponto), devemos regredir mais ainda o nosso caminho. A maneira que percorremos esse labirinto conhecida como busca em profundidade: v amos nos aprofundando no caminho atual at no poder mais, e s quando no der mais volt amos a profundidade do caminho para tentar outra alternativa. Busca em Profundidade est muito relacionada ao uso de uma Pilha, e tambm pode ser realizada com o uso de recurso. O algoritmo sempre funciona, desde que haja sada e que voc seja mais rpido que o fa tal Minotauro! Agora a melhor hora de aprender algo novo

Se voc gosta de estudar essa apostila aberta da Caelum, certamente vai gostar dos novos cursos online que lanamos. Voc estuda a qualquer momento com a qualidade Ca elum. Conhea a assinatura semestral. 6.9 - Exerccios: Pilha Implemente a classe Peca no pacote br.com.caelum.ed para poder criar objetos. package br.com.caelum.ed; public class Peca { private String nome; public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } } Implemente a classe Pilha para peas vista neste captulo. Coloque a classe no pacot e br.com.caelum.ed.pilhas package br.com.caelum.ed.pilhas; import java.util.LinkedList; import java.util.List; import br.com.caelum.ed.Peca; public class Pilha { private List<Peca> pecas = new LinkedList<Peca>(); public void insere(Peca peca) { this.pecas.add(peca); } public Peca remove() { return this.pecas.remove(this.pecas.size() - 1); } public boolean vazia() { return this.pecas.size() == 0; } } Faa alguns testes. package br.com.caelum.ed.pilhas; import br.com.caelum.ed.Peca; public class Teste { public static void main(String[] args) { Pilha pilha = new Pilha(); Peca peca = new Peca();

pilha.insere(peca); Peca pecaRemovida = pilha.remove(); if(peca != pecaRemovida){ System.out.println("Erro: a pea removida no igual " + " a que foi inserida"); } if (!pilha.vazia()) { System.out.println("Erro: A pilha no est vazia"); } } } Se no for impresso nenhuma mensagem de erro significa que a Pilha est funcionando. Implemente a classe PilhaGenerica para objetos (genrica) vista neste captulo. Colo que a classe no pacote br.com.caelum.ed.pilhas package br.com.caelum.ed.pilhas; import java.util.LinkedList; import java.util.List; public class PilhaGenerica { private List<Object> objetos = new LinkedList<Object>(); public void insere(Object objeto) { this.objetos.add(objeto); } public Object remove() { return this.objetos.remove(this.objetos.size() - 1); } public boolean vazia() { return this.objetos.size() == 0; } } Faa alguns testes. package br.com.caelum.ed.pilhas; import br.com.caelum.ed.Peca; public class TestePilhaGenerica { public static void main(String[] args) { PilhaGenerica pilhaDePecas = new PilhaGenerica(); Peca peca = new Peca(); pilhaDePecas.insere(peca); Peca pecaRemovida = pilhaDePecas.remove(); if(peca != pecaRemovida){ System.out.println("Erro: a pea removida no igual " + " a que foi inserida"); }

if (!pilhaDePecas.vazia()) { System.out.println("Erro: A pilha no est vazia"); } } } Perceba que a classe TestePilhaGenerica contm um erro de compilao. Quando voc remove um elemento da PilhaGenerica voc recebe uma referncia do tipo Object e no do tipo Peca. Altere a linha: Peca pecaRemovida = pilhaDePecas.remove(); Por: Object pecaRemovida = pilhaDePecas.remove(); Isso faz o cdigo compilar mas agora voc no tem mais a garantia de tipo. No sabe se a referncia que voc recebeu realmente est apontado para um objeto do tipo Peca. Implemente a classe PilhaParametrizada utilizando o recurso do Generics. Coloque a classe no pacote br.com.caelum.ed.pilhas package br.com.caelum.ed.pilhas; import java.util.LinkedList; import java.util.List; public class PilhaParametrizada<T> { private List<T> objetos = new LinkedList<T>(); public void insere(T t) { this.objetos.add(t); } public T remove() { return this.objetos.remove(this.objetos.size() - 1); } public boolean vazia() { return this.objetos.size() == 0; } } Faa alguns testes: package br.com.caelum.ed.pilhas; import br.com.caelum.ed.Peca; public class TestePilhaGenerica { public static void main(String[] args) { PilhaParametrizada<Peca> pilhaDePecas = new PilhaParametrizada<Peca>(); Peca peca = new Peca(); pilhaDePecas.insere(peca); Peca pecaRemovida = pilhaDePecas.remove(); if(peca != pecaRemovida){ System.out.println("Erro: a pea removida no igual " +

" a que foi inserida"); } if (!pilhaDePecas.vazia()) { System.out.println("Erro: A pilha no est vazia"); } PilhaParametrizada<String> pilhaDeString = new PilhaParametrizada<String>(); pilhaDeString.insere("Manoel"); pilhaDeString.insere("Zuleide"); System.out.println(pilhaDeString.remove()); System.out.println(pilhaDeString.remove()); } }