Dinamicas
-
Upload
ialis-cavalcante -
Category
Education
-
view
1.374 -
download
1
Transcript of Dinamicas
Variáveis Dinâmicas, Abstração e RecursividadeTécnicas de ProgramaçãoProf. Iális CavalcanteEngenharia da Computação2011.1
VARIÁVEIS DINÂMICAS
Introdução
Alguns tópicos a serem discutidos inicialmente:◦ Sistema analógico x digital◦ Computador◦ Software◦ Linguagem de programação◦ Compilador◦ Dinâmica x estática
Introdução
Sistema analógico◦ Pode assumir infinitos valores dentro de
determinados intervalos
Sistema digital◦ Assume valores discretos binários (0 ou 1)
Etimologia: latim -> digitus -> significa dedoQuant. finita de dedos -> sistema decimal (10 dedos)
IntroduçãoComputador◦ Máquina que realiza processamento de dados◦ Sistema físico que realiza algum tipo de
computação◦ Arquitetura -> digital -> John von Neumann
Memória
Unidade deControle
UnidadeLógica
Aritmética
E/Sdados
instruções
Introdução
Software◦ Seqüência de instruções a serem seguidas
pelo computador para alcançar um resultado.Executado pelo processador ou máquina virtual;Construído por uma linguagem de programação
Linguagem de Programação◦ Conjunto de regras usada para transformar
os comandos de um programa em instruções para o computador
IntroduçãoCompilador◦ Programa que, a partir do código escrito em uma
linguagem (código-fonte), cria um programa escrito em outra linguagem (código-objeto).
Análise léxica, sintática e semântica.
Dinâmica◦ Parte da física que estuda os movimentos e suas
causas (Mecânica).◦ Iniciada por Newton e presente na segunda lei:
A taxa de variação no tempo da quantidade de movimento de um objeto é igual à soma das forças aplicadas no mesmo.
Variáveis Dinâmicas
Estático x Dinâmico◦ A verificação do tipo de dado é feita de forma
estática em tempo de compilação, ou de forma dinâmica em tempo de execução.
Ponteiro◦ Tipo de dado cujo valor se refere
diretamente a um outro valor alocado em outra área de memória, através de seu endereço.
Variáveis Dinâmicas
Ponteiro é o principal tipo de dado utilizado na alocação dinâmica de variáveis.Em Java, esta alocação é implícita, sem descrição direta dos ponteiros e seus endereços de memória.Essa responsabilidade fica por conta da ferramenta presente na JVM: Coletor de Lixo (Garbage Colector, ou somente GC).
Variáveis DinâmicasEm C:
#include <stdio.h>
void altera (int *n) { *n = 120; }
int main(){
int x = 24;
int *endereco = &x; /* o operador ‘&’ (referência) retorna o endereço de uma variável */
printf(“%d \n”, x); /* descreve valor de x */
printf(“%p \n”,endereco); /* descreve o endereço de x */
altera(&x); /* passa o endereço de x como referência, para alteração */
printf(“%d \n”,x); /* mostra o novo valor de x */
printf(“%p %p \n”,endereco,&x); /* note que o endereço de x não foi alterado*/
return 0;
}
Variáveis DinâmicasEm Java:
public class Principal{public static void main(String args[]){
Ponto p1, p2;p1 = new Ponto();p1.x = 3; p1.y = 1;p2 = p1; // atribuindo referência ao objeto p1p1.x = 5;System.out.println(“Valores de p1: ”+p1.x+“ e ”+p1.y);System.out.println(“Valores de p2: ”+p2.x+“ e ”+p2.y);
}
}
class Ponto{
public int x;
public int y;
Ponto(){}
}
Variáveis Dinâmicas
Atribuir uma referência faz com que ambas apontem para o mesmo objeto. Qualquer alteração afeta as duas variáveis.
p1
p1
p1
p2
p2
p2
x
x
x
y
y
y
. . .
3
15
1
13
p2 = p1;
p1.x = 5;
Variáveis DinâmicasEm Java, todos os tipos primitivos são representados por valores:◦ char c; c = ‘a’;◦ int x, y; x = y = 3;
Os tipos compostos (arrays e classes) utilizam referências:◦ String s; s = “if672”;◦ Ponto p; p = new Ponto(3,1); p.x = x;◦ Integer n; n = new Integer(3);◦ ArrayList v; v = null;
Alocação dinâmica de memória
A memória só é requisitada no momento em que o objeto é necessário, evitando o desperdício. Isso ocorre através do operador new:◦ Ponto p = new Ponto(800,600);◦ Parâmetros do Construtor
A memória é alocada para o novo objeto, e sua posição armazenada em uma referência (ponteiro).
Alocação dinâmica de memória
Código-Fonte Memória
int[ ] a;int[ ] b;
a = new int[7];b = new int[4];
a = b;
. . .
. . .
1a b
1
Alocação dinâmica de memória
Código-Fonte Memória
int[ ] a;int[ ] b;
a = new int[7];b = new int[4];
a = b;
. . .
. . .2
int [ 4 ]
int [ 7 ]
a b
2
Alocação dinâmica de memória
Código-Fonte Memória
int[ ] a;int[ ] b;
a = new int[7];b = new int[4];
a = b;
. . .
. . .3
int [ 4 ]
int [ 7 ]
a b
3
Não há mais ponteiro para essa região. O que acontece com ela?
Alocação dinâmica de memóriaÉ possível então desalocar as variáveis antes de eliminar a última referência para ela. Em Java, isso não é necessário, pois o garbage collector libera a memória automaticamente.◦ Para chamar diretamente a GC: System.gc();
Destruição de objetos em Java:◦ explícita: objeto = null;◦ implícita: contexto (gerenciamento pelo GC)
fim da execução do método;ocorrência de uma exceção;perca da referencia: objeto2 = objeto1;
Alocação dinâmica de memória
Coletor de lixo: retira da memória objetos não usados.Exemplo:
Ator a3 = new Ator(“Claudia”,22, ‘f ’);System.out.println(a3.nome);a3 = null;System.out.println(a3.nome);Exceção: java.lang.NullPointerException
Programa Memória Heap
Objeto X
Y = X
Objeto Y Objeto podeficar semreferência
Estruturas de dados dinâmicasListas encadeadas◦ São coleções de itens de dados “colocados em fila” e as
inserções e exclusões podem ser feitas em qualquer lugar (início ou final);
Pilhas◦ Inserções e exclusões são feitas apenas em uma extremidade
(parte superior – topo – LIFO). São de importante uso em compiladores e sistemas operacionais.
Filas◦ As inserções são feitas na parte de trás (cauda) de uma fila e as
exclusões são feitas a partir da parte da frente (cabeça) –FIFO.
Estruturas de dados dinâmicas
Arrays x Listas◦ Arrays podem ocupar espaço desnecessário
na memória, mas seu acesso é feito diretamente.◦ Listas ocupam apenas o espaço necessário,
mas é preciso espaço extra para armazenar as referências.
Além disso, seu acesso é seqüencial.
Estruturas de dados dinâmicasClasses auto-referenciais: contêm uma variável de instância que faz referência a outro objeto do mesmo tipo de classe.
class No{
private String dado;
private No proxNo; // próximo Nó – referência
public No (String dado) { /* corpo do construtor */
setProxNo(null); }public void setDado (String dado) { /* corpo do método */ }
public String getDado () { }
public void setProxNo (No prox) { }
public No getProxNo () { }
}
Estruturas de dados dinâmicasOs programas podem encadear objetos auto-referenciais para formar estrutura de dados úteis como listas, filas, pilhas e árvores. Permitindo assim uma alocação dinâmica de memória:◦ capacidade de um programa obter mais espaço de
memória durante a execução para armazenar novos nós e liberar espaço não mais necessário.
O limite para alocação dinâmica pode ser tão grande quanto a quantidade de memória física disponível no computador.
Estruturas de dados dinâmicasListas: a construção é feita a partir de ponteiros/referências.
Geralmente contém uma referência para o primeiro elemento da lista (No inicio), a partir do qual todos os outros poderão ser acessados.
5 8 1 4 \
3 1 2L X
Dado armazenadono nó atual
Referência para opróximo elemento
da lista
Indicador dofim da lista
Estruturas de dados dinâmicas
Inserção em listas:◦ Se a lista estiver vazia:
◦ Caso contrário, inserir no fim da lista:
3L XX
3 1 2L X
9 Xúltimo nó?NÃO!
último nó?NÃO!
último nó?SIM!
novo nó
Estruturas de dados dinâmicasPara inserir um novo nó entre outros dois:
No novoNo = new No(5);
novoNo.next = anterior.next;
anterior.next = novoNo;
4 7. . . . . .
5 X
anterior anterior.next
novoNoanterior.next
Estruturas de dados dinâmicasRemoção em listas:
◦ Para excluir um nó entre outros dois:
anterior.next = anterior.next.next;
1 9 2. . . . . .anterior nó atual anterior.next.next
anterior.next
X
ABSTRAÇÃO
Abstração
Tipo de Dados◦ Caracteriza o conjunto de valores a que uma
constante pertence, ou que podem ser assumidos por uma variável ou expressão, ou que podem ser gerados por uma função.
Abstração
Tipo Abstrato de Dados◦ Pode ser visto como um modelo matemático,
acompanhado das operações definidas sobre o modelo. O conjunto dos inteiros acompanhado das operações de adição, subtração e multiplicação forma um exemplo de um tipo abstrato de dados.
Abstração x Encapsulamento
Abstração◦ Cliente não precisa saber mais do que o
especificado na interface para usar em uma classe;
Encapsulamento◦ Cliente não consegue saber nada sobre uma
classe além do que está expresso em sua interface.
Interface
Interface -> ModeloPalavra chave: implementsExemplo: formas Ponto e Circulo
Interface - Exemplo
package aula.abstracao;public interface Forma {
// calcula a áreapublic abstract double area();// devolve o nome da figurapublic abstract String getNome();
}
Interface - Exemplopackage aula.abstracao;
public class Ponto implements Forma{
private int x,y;
public Ponto(){ setPonto(0,0); }
public Ponto(int coordX, int coordY){ setPonto(coordX,coordY); }
public void setPonto(int coordX, int coordY){
setX(coordX); setY(coordY);
}
(...) /** métodos de acesso aos atributos privados */
public String toString(){ return "["+x+", "+y+"]"; } // herda de Object
public double area(){ return 0.0; } // segue a interface
public String getNome(){ return "Ponto"; } // segue a interface
}
Interface - Exemplopackage aula.abstracao;
public class Circulo implements Forma{
private int x,y; private double raio;
public Circulo(){ setCirculo(0,0,0.0); }
public Circulo(int coordX, int coordY, double r){
setCirculo(coordX, coordY, r); }
public void setCirculo(int coordX, int coordY, double r){
setX(coordX); setY(coordY); setRaio(r);
}
(...) /** métodos de acesso aos atributos privados */
public String toString(){ return "Centro = ["+x+", "+y+"] e Raio = "+raio; }
public double area(){ return Math.PI*raio*raio; } // segue a interface
public String getNome(){ return "Círculo"; } // segue a interface
}
Interface - Exemplopackage aula. abstracao;
public class TesteInterface {
public static void main(String args[]){
// cria formas
Ponto ponto = new Ponto(7,11);
Circulo circulo = new Circulo(22,8,3.5);
Ponto ponto2 = new Ponto(81,25);
// cria array de formas
Forma arrayDeFormas[] = new Forma[3];
// aponta arrayDeFormas[0] para o ojbeto da subclasse Ponto
arrayDeFormas[0] = ponto;
arrayDeFormas[1] = circulo;
arrayDeFormas[2] = ponto2;
(...)
Interface - ExemploString output = " ";
// obtém o nome e a representação de cada forma
for(int i = 0; i < arrayDeFormas.length; i++){
output += "\n\n"+arrayDeFormas[i].getNome()+
": "+arrayDeFormas[i].toString()+
"\nÁrea = "+arrayDeFormas[i].area();
}
System.out.println(output);
}
}
Interface - Exemplo
Saída:
Ponto: [7, 11]Área = 0.0
Círculo: Centro = [22, 8] e Raio = 3.5Área = 38.48451000647496
Ponto: [81, 25]Área = 0.0
Classes e métodos abstratosClasses abstratas:◦ Classes que são demasiadamente gerais para criar
objetos reais.◦ Utilizadas somente como superclasses abstratas para
subclasses concretas e para declarar variáveis de referência.◦ Muitas hierarquias de herança têm superclasses
abstratas que ocupam os poucos níveis superiores.◦ Palavra-chave abstract:
Utilize para declarar uma classe abstract.Também utilize para declarar um método abstract:
As classes abstratas normalmente contêm um ou mais métodos abstratos.Todas as subclasses concretas devem sobrescrever todos os métodos abstratos herdados.
Classes e métodos abstratos
Classe Iteradora:◦ Pode percorrer todos os objetos em uma
coleção, como um array ou um ArrayList.◦ Os iteradores são freqüentemente utilizados na
programação polimórfica para percorrer uma coleção que contém referências a objetos provenientes de vários níveis de uma hierarquia.
Classes e métodos abstratosUma classe abstrata declara atributos e comportamentos comuns das várias classes em uma hierarquia de classes.Em geral, uma classe abstrata contém um ou mais métodos abstratos que as subclasses devem sobrescrever se as subclasses precisarem ser concretas.Variáveis de instância e métodos concretos de uma classe abstrata estão sujeitos às regras normais da herança.
Classes e métodos abstratosTentar instanciar um objeto de uma classe abstrata é um erro de compilação.
Não implementar os métodos abstratos de uma superclasse em uma subclasse é um erro de compilação, a menos que a subclasse também seja declarada abstract.
Classes e métodos abstratosUma subclasse pode herdar a ‘interface’ ou ‘implementação’ de uma superclasse.◦ Hierarquias projetadas para a herança de
implementação tendem a ter suas funcionalidades na parte superior da hierarquia
cada nova subclasse herda um ou mais métodos que foram implementados em uma superclasse e a subclasse utiliza essas implementações de superclasse.
◦ As hierarquias projetadas para a herança de interfacetendem a ter suas funcionalidades na parte inferior da hierarquia
uma superclasse especifica um ou mais métodos abstratos que devem ser declarados para cada classe concreta na hierarquia; e as subclasses individuais sobrescrevem esses métodos para fornecer implementações específicas de subclasses.
Classes e métodos abstratos
Ponto
Circulo
Cilindro
Forma
Ponto
Circulo
Cilindro
Herança deImplementação
Herança deInterface
Classes e métodos abstratosSuperclasse Abstrata:public abstract class Forma {
private int x; private int y;
public Forma(int x, int y){
this.x = x; this.y = y;
}
public void setX(int x){ this.x = x; }
public void setY(int y){ this.y = y; }
public int getX(){ return this.x; }
public int getY(){ return this.y; }
public String toString(){
return String.format("(%d, %d)", getX(), getY());
}
public abstract String getNome(); // método abstrato
}
Classes e métodos abstratospublic abstract class FormaBidimensional extends Forma{
private int dimensao1;
private int dimensao2;
public FormaBidimensional(int x, int y, int d1, int d2){
super(x, y);
dimensao1 = d1;
dimensao2 = d2;
}
public void setDimensao1(int d1){ dimensao1 = d1; }
public void setDimensao2(int d2){ dimensao2 = d2; }
public int getDimensao1(){ return dimensao1; }
public int getDimensao2(){ return dimensao2; }
public abstract int getArea(); // método abstrato
}
Classes e métodos abstratospublic class Circulo extends FormaBidimensional {
public Circulo(int x, int y, int raio){
super(x, y, raio, raio);
}
//método sobrecarregado de Forma
public String getNome(){ return "Círculo"; }
//método sobrecarregado de FormaBidimensional
public int getArea(){ return (int) (Math.PI*getRaio()*getRaio()); }
public int getRaio(){ return getDimensao1(); }
public void setRaio(int raio){ setDimensao1(raio); }
public String toString(){
return String.format("%s %s: %d\n", super.toString(), "raio", getRaio());
}
}
Classes e métodos abstratospublic class Quadrado extends FormaBidimensional {
public Quadrado(int x, int y, int lado){
super(x, y, lado, lado);
}
//método sobrecarregado de Forma
public String getNome(){ return "Quadrado"; }
//método sobrecarregado de FormaBidimensional
public int getArea(){ return getLado()*getLado(); }
public int getLado(){ return getDimensao1(); }
public void setLado(int raio){
setDimensao1(raio);
setDimensao2(raio);
}
public String toString(){
return String.format("%s %s: %d\n", super.toString(), "lado", getLado());
}
}
Classes e métodos abstratospublic class TesteForma {
public static void main(String args[ ]){
Forma formas[ ] = new Forma[3];
formas[0] = new Circulo(22,88,4);
formas[1] = new Quadrado(71,96,10);
formas[2] = new Circulo(8,89,2);
System.out.println();
for(int ind = 0; ind < formas.length; ind++){
System.out.printf("%s: %s",formas[ind].getNome(),formas[ind].toString());
FormaBidimensional forma2D = (FormaBidimensional) formas[ind];
System.out.printf("Área de %s é %s\n", formas[ind].getNome(), forma2D.getArea());
System.out.println();
}
}
}
Classes e métodos abstratosSaída – exemplo:
Círculo: (22, 88) raio: 4Área de Círculo é 50
Quadrado: (71, 96) lado: 10Área de Quadrado é 100
Círculo: (8, 89) raio: 2Área de Círculo é 12
RECURSIVIDADE
Introdução
Programas anteriores estruturados como métodos chamam uns aos outros de uma maneira hierárquica e disciplinada.Métodos recursivos:◦ chamam a si mesmos,◦ úteis para alguns problemas a fim de definir
uma chamada ao próprio método; e◦ podem ser chamados direta ou indiretamente
por um outro método.
Conceitos de recursãoElementos recursivos de solução de problemas:◦ Caso básico:
Método recursivo só é capaz de resolver o caso mais simples — o caso básico.Se o método for chamado com o caso básico, o método retorna um resultado.
◦ Se o método for chamado com um problema mais complexo, o problema será dividido em duas partes — uma parte que o método sabe o que fazer e uma outra que o método não sabe o que fazer (denominada chamada recursiva ou passo de recursão).
◦ Chamada recursiva/passo de recursão:Deve assemelhar-se ao problema original, porém ser um pouco mais simples ou a menor versão.O método chama uma cópia atualizada dele mesmo a fim de trabalhar em um problema menor.Normalmente, inclui uma instrução return
Recursão indireta:◦ O método recursivo chama um outro método que, conseqüentemente,
faz uma chamada de volta ao método recursivo.
Exemplo que utiliza recursão:FatoriaisFatorial de n, ou n! é o produto◦ n · (n – 1) · (n – 2) · … · 1
◦ Com 1! igual a 1 e 0! definido como 1.Pode ser resolvido recursiva ou iterativamente (não-recursivamente).Solução recursiva utiliza o relacionamento a seguir:◦ n! = n · (n – 1)!Recursão infinita – chamadas recursivas são feitas continuamente até que a memória tenha sido exaurida.
◦ É causada omitindo o caso básico ou escrevendo um passo de recursão que não converge com o caso básico.
Avaliação recursiva de 5!.
public class FactorialCalculator {
// método fatorial recursivo
public long factorial( long number ) {
if ( number <= 1 ) // testa caso básico
return 1; // casos básicos: 0! = 1 e 1! = 1
else // passo de recursão
return number * factorial( number ‐ 1 );
} // fim do método fatorial
// gera saída de fatoriais para valores 0‐10
public void displayFactorials() {
// calcula os fatoriais de 0 a 10
for ( int counter = 0; counter <= 10; counter++ )
System.out.printf( "%d! = %d\n", counter, factorial( counter ) );
} // fim do método displayFactorials
} // fim da classe FactorialCalculator
public class FactorialCalculator {
// método fatorial recursivo
public long factorial( long number ) {
if ( number <= 1 ) // testa caso básico
return 1; // casos básicos: 0! = 1 e 1! = 1
else // passo de recursão
return number * factorial( number ‐ 1 );
} // fim do método fatorial
// gera saída de fatoriais para valores 0‐10
public void displayFactorials() {
// calcula os fatoriais de 0 a 10
for ( int counter = 0; counter <= 10; counter++ )
System.out.printf( "%d! = %d\n", counter, factorial( counter ) );
} // fim do método displayFactorials
} // fim da classe FactorialCalculator
Caso básico retorna 1
Método de porção sabe o que fazer
Passo de recursão divide o problema em duas partes: com uma o método sabe como fazer;
com outra, não
Chamada recursiva: O método portion não sabe como fazer; a menor versão do problema
original
Chamada original ao método recursivo
public class FactorialTest { // calcula fatoriais de 0‐10
public static void main( String args[] ) {
FactorialCalculator factorialCalculator = new FactorialCalculator();
factorialCalculator.displayFactorials();
} // fim de main
} // fim da classe FactorialTest
Saída:
0! = 11! = 12! = 23! = 64! = 245! = 1206! = 7207! = 50408! = 403209! = 36288010! = 3628800
Calcula e exibe fatoriais
Nota:
•Omitir o caso básico ou escrever o passo derecursão incorretamente provoca erro!
•Se de alguma forma isso não convirja para o casobásico pode causar um erro de lógica conhecidocomo recursão infinita.
•Neste caso, as chamadas recursivas são feitascontinuamente até acabar a memória.
•Isso é análogo ao problema de um loop infinito emuma solução iterativa (não recursiva).
Exemplo que utiliza recursão: Série de Fibonacci
A série de Fibonacci inicia com 0 e 1 e tem a propriedade de que cada número de Fibonacci subseqüente é a soma dos dois números de Fibonacci anteriores.A série ocorre na natureza; a taxa de números de Fibonacci sucessivos converge de acordo com a taxa ou a média áurea.Fibonacci, série definida recursivamente como:◦ fibonacci(0) = 0◦ fibonacci(1) = 1◦ fibonacci(n) = fibonacci(n – 1) + fibonacci(n – 2)Solução recursiva para cálculo de valores de Fibonacci resulta na explosão das chamadas de métodos recursivos.
public class FibonacciCalculator {
// declaração recursiva do método fibonacci
public long fibonacci( long number ) {
if ( ( number == 0 ) || ( number == 1 ) ) // casos básicos
return number;
else // passo de recursão
return fibonacci( number ‐ 1 ) + fibonacci( number ‐ 2 );
} // fim do método fibonacci
public void displayFibonacci() {
for ( int counter = 0; counter <= 10; counter++ )
System.out.printf( "Fibonacci of %d is: %d\n", counter, fibonacci( counter ) );
} // fim do método displayFibonacci
} // fim da classe FibonacciCalculator
Dois casos básicos
Duas chamadas recursivas
Chamada original ao método recursivo
public class FibonacciTest {
public static void main( String args[] ) {
FibonacciCalculator fibonacciCalculator = new FibonacciCalculator();
fibonacciCalculator.displayFibonacci();
} // fim de main
} // fim da classe FibonacciTest
Saída:
Fibonacci of 0 is: 0Fibonacci of 1 is: 1Fibonacci of 2 is: 1Fibonacci of 3 is: 2Fibonacci of 4 is: 3Fibonacci of 5 is: 5Fibonacci of 6 is: 8Fibonacci of 7 is: 13Fibonacci of 8 is: 21Fibonacci of 9 is: 34Fibonacci of 10 is: 55
Calcula e exibe os valores de Fibonacci
Nota:
Evite programas recursivos noestilo Fibonacci, porque resultamem uma ‘explosão’ exponencial dechamadas de método.
Conjunto de chamadas recursivas para fibonacci( 3 ).
Recursão e a pilha de chamadas do método
Pilha de chamadas de método utilizadas para monitorar chamadas ao método e variáveis locais dentro de uma chamada de método.Assim como ocorre com a programação não-recursiva, chamadas de métodos recursivos são colocadas na parte superior da pilha das chamadas de método.À medida que retornam as chamadas ao método recursivo, seus registros de ativação são retirados da pilha e as chamadas recursivas prévias continuam a executar.Método atual em execução sempre é o método cujo registro de ativação está na parte superior da pilha.
Chamadas do método feitas dentro da chamada fibonacci( 3 ).
Chamadas do método na pilha de execução do programa.
Recursão versus iteraçãoQualquer problema que possa ser resolvido de modo recursivo também pode ser resolvido iterativamente.Tanto a iteração como a recursão utilizam uma instrução de controle.◦ A iteração utiliza uma instrução de repetição.◦ A recursão utiliza uma instrução de seleção.Iteração e recursão envolvem um teste de terminação.◦ A iteração termina quando a condição de
continuação do loop falha.◦ A recursão termina quando um caso básico é
alcançado.A recursão pode demandar muito tempo de processador e espaço de memória, mas normalmente fornece uma solução mais intuitiva.
Recursão versus iteraçãoQualquer problema que pode ser resolvido de modo recursivo também pode ser resolvido iterativamente(não recursivamente).Uma abordagem recursiva em geral é preferida sobre uma abordagem iterativa quando a abordagem recursiva espelha mais naturalmente o problema e resulta em um programa mais fácil de entender e depurar.Uma abordagem recursiva pode ser freqüentemente implementada com menos linhas de código. Outra razão de escolher uma abordagem recursiva é que uma iterativa talvez não seja aparente.
public class FactorialCalculator {
// declaração recursiva de método factorial
public long factorial( long number ) {
long result = 1;
// declaração iterativa de método factorial
for ( long i = number; i >= 1; i‐‐ )
result *= i;
return result;
} // fim do método factorial
// gera saída de fatoriais para valores 0‐10
public void displayFactorials() {
// calcula os fatoriais de 0 a 10
for ( int counter = 0; counter <= 10; counter++ )
System.out.printf( "%d! = %d\n", counter, factorial( counter ) );
} // fim do método displayFactorials
} // fim da classe FactorialCalculator
Solução iterativa utiliza a repetição controlada por contador
public class FactorialTest {
// calcula fatoriais de 0‐10
public static void main( String args[] ) {
FactorialCalculator factorialCalculator = new FactorialCalculator();
factorialCalculator.displayFactorials();
} // fim de main
} // fim da classe FactorialTest
Saída:
0! = 11! = 12! = 23! = 64! = 245! = 1206! = 7207! = 50408! = 403209! = 36288010! = 3628800
Nota:
Evite utilizar a recursão em situações querequerem alto desempenho. Chamadasrecursivas levam tempo e consomemmemória adicional.
Ter acidentalmente um método não recursivochamando a si próprio seja direta ouindiretamente por outro método pode causarrecursão infinita.
Permutações de stringPermutações de uma string de texto – todas as diferentes strings que podem ser criadas reorganizando os caracteres da string original.As palavras criadas a partir das permutações são conhecidas como anagramas.Solução recursiva: Remover um dos caracteres, localizar permutações dos caracteres remanescentes (caso recursivo), combina permutações com o caractere que foi removido.Caso básico: Localizar permutações para apenas um caractere – o próprio caractere é a única permutação.Qualquer string fornece n! permutações para ncaracteres.
public class Permutation {
// declaração recursiva do método permuteString
private void permuteString(String beginningString, String endingString ) {
// caso básico: se string a permutar tiver comprimento menor que ou igual
// 1, exibe apenas essa string concatenada com beginningString
if ( endingString.length() <= 1 )
System.out.println( beginningString + endingString );
else { // passo de recursão: permuta endingString para cada caractere em endingString
for ( int i = 0; i < endingString.length(); i++ ){
try {
// cria nova string para permutar eliminando o caractere no índice i
String newString = endingString.substring( 0, i ) + endingString.substring( i + 1 );
// chamada recursiva com uma nova string a ser permutada
// e uma string inicial a ser concatenada, que inclui o caractere no índice i
permuteString( beginningString + endingString.charAt( i ), newString );
} catch ( StringIndexOutOfBoundsException exception ) {
exception.printStackTrace(); } // fim do catch
} // fim do for
} // fim do else
} // fim do método permuteString
} // fim da classe Permutation
Caso básico: Combinar caracteres removidos (beginningString) com endingString, que é
somente um caractere
Remove um caractere; localizaremos permutações para os caracteres remanescentes
Chamada recursiva: localizar permutações para os caracteres remanescentes e, então, reanexar os caracteres removidos
public class PermutationTest {
public static void main( String args[] ) {
Scanner scanner = new Scanner( System.in );
Permutation permutationObject = new Permutation();
System.out.print( "Enter a string: " );
String input = scanner.nextLine(); // recupera String a permutar
// permuta String
permutationObject.permuteString( "", input );
} // fim de main
} // fim da classe PermutationTest
Chamada inicial ao método recursivo; ainda não há caracteres removidos, assim o primeiro argumento é “”
Saída:
mathmahtmtahmthamhatmhtaamthamhtatmhathmahmtahtmtmahtmhatamhtahmthmathamhmathmtahamthatmhtmahtam
Torres de HanóiProblema clássico: Sacerdotes no Extremo Oriente estão tentando mover uma pilha de discos de um pino para outro. Um dos discos deve ser movido em um determinado momento; em nenhum momento um disco maior pode ser posicionado acima de um disco menor.Solução recursiva:◦ Mova os n – 1 discos do pino 1 para o pino 2, utilizando o pino 3
como área de armazenamento temporário.◦ Mova o último disco (o maior) do pino 1 para o pino 3.◦ Mova os n – 1 discos do pino 2 para o pino 3, utilizando o pino 1
como área de armazenamento temporário.Caso básico: Quando somente um disco precisa ser movido, nenhuma área de armazenamento temporário é necessária; o disco é simplesmente movido.
Torres de Hanói para o caso com quatro discos.
public class TowersOfHanoi {
int numDisks; // número de discos a serem movidos
public TowersOfHanoi( int disks ) {
numDisks = disks;
} // fim do construtor TowersOfHanoi
// move recursivamente os discos pelas torres
public void solveTowers( int disks, int sourcePeg, int destinationPeg, int tempPeg ) {
// caso básico – apenas um disco a ser movido
if ( disks == 1 ) {
System.out.printf( "\n%d ‐‐> %d", sourcePeg, destinationPeg );
return;
} // fim do if
// passo de recursão ‐‐move o disco para tempPeg, e depois para destinationPeg
// move ( disks ‐ 1 ) discos de sourcePeg para tempPeg recursivamente
solveTowers( disks ‐ 1, sourcePeg, tempPeg, destinationPeg );
// move o último disco de sourcePeg para destinationPeg
System.out.printf( "\n%d ‐‐> %d", sourcePeg, destinationPeg );
// ‐ move ( disks ‐ 1 ) discos de tempPeg para destinationPeg
solveTowers( disks ‐ 1, tempPeg, destinationPeg, sourcePeg );
} // fim do método solveTowers
} // fim da classe TowersOfHanoi
Caso básico: simplesmente exibe o movimento
Move n-1 discos do compartimento 1 para o compartimento 2
Move o último disco no compartimento 1 para o compartimento 3
Move n-1 discos do compartimento 2 para o compartimento 3
Usa o compartimento 1 como a área de armazenamento temporário
Usa o compartimento 3 como a área de armazenamento temporário
public class TowersOfHanoiTest {
public static void main( String args[] ) {
int startPeg = 1; // valor 1 utilizado para indicar startPeg na saída
int endPeg = 3; // valor 3 utilizado para indicar endPeg na saída
int tempPeg = 2; // valor 2 utilizado para indicar tempPeg na saída
int totalDisks = 3; // número de discos
TowersOfHanoi towersOfHanoi = new TowersOfHanoi( totalDisks );
// chamada não‐recursiva inicial: move todos os discos.
towersOfHanoi.solveTowers( totalDisks, startPeg, endPeg, tempPeg );
} // fim de main
} // fim da classe TowersOfHanoiTest
Saída:
1 ‐‐> 31 ‐‐> 23 ‐‐> 21 ‐‐> 32 ‐‐> 12 ‐‐> 31 ‐‐> 3
Faz a chamada inicial ao método recursivo
FractaisUm fractal – uma figura geométrica que freqüentemente pode ser gerada a partir de um padrão repetido recursivamente por um número infinito de vezes.Padrão aplicado a cada segmento da figura original.Benoit Mandelbrot introduziu o termo ‘fractal’, juntamente com especificidades de como os fractais são criados e de suas aplicações práticas.◦ Ajuda a melhor entender os padrões na natureza,
o corpo humano e o universo.◦ Forma de arte popular.
FractaisPropriedade auto-semelhante – os fractais têm essa propriedade na eventualidade de que, quando subdivididos em partes, cada um se assemelhe a uma cópia de tamanho reduzido do todo.Se a parte for uma cópia exata do original, dizemos que o fractal é estritamente auto-semelhante.Toda vez que um padrão é aplicado, dizemos que o fractal está em um novo nível ou profundidade.Exemplos de fractais: Curva de Koch, Floco de neve de Koch.
Fractal Curva de Koch.
(a) (b)
c) (d)
(e) (f)
Retorno recursivoReversão recursiva – processo de utilização da recursão para retornar ao ponto de decisão anterior.Se um conjunto de chamadas recursivas não resultar em uma solução, o programa volta ao ponto de decisão e toma uma decisão diferente, resultando freqüentemente em outro conjunto de chamadas recursivas.Exemplos:◦ Problema do labirinto.◦ Problema das Oito Rainhas.