• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Dinamicas
 

Dinamicas

on

  • 1,692 views

 

Statistics

Views

Total Views
1,692
Views on SlideShare
1,692
Embed Views
0

Actions

Likes
0
Downloads
41
Comments
0

0 Embeds 0

No embeds

Accessibility

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Dinamicas Dinamicas Presentation Transcript

    • Variáveis Dinâmicas, Abstraçãoe 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 dedo Quant. finita de dedos -> sistema decimal (10 dedos)
    • Introdução Computador ◦ Máquina que realiza processamento de dados ◦ Sistema físico que realiza algum tipo de computação ◦ Arquitetura -> digital -> John von Neumann Memória instruções Unidade Unidade de Lógica Controle Aritmética dados E/S
    • 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ção Compilador ◦ 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âmicas Em 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âmicas Em 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 p1 p1.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 3 1 p2 ... x y p1 3 1 p2 p2 = p1; x y p1 5 1 p2 p1.x = 5; x y
    • Variáveis Dinâmicas Em 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; a b 1 int[ ] b; ... a = new int[7]; b = new int[4]; ... a = b; 1
    • Alocação dinâmica de memória Código-Fonte Memória int[ ] a; a b int[ ] b; ... a = new int[7]; 2 b = new int[4]; int [ 7 ] ... a = b; int [ 4 ] 2
    • Alocação dinâmica de memória Código-Fonte Memória int[ ] a; a b int[ ] b; ... a = new int[7]; b = new int[4]; int [ 7 ] ... 3 a = b; int [ 4 ] 3Nã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 Programa Memória Heap Objeto X Y = X Objeto Y Objeto pode ficar sem referência 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
    • Estruturas de dados dinâmicas Listas 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âmicas Classes 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âmicas Os 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âmicas Listas: a construção é feita a partir de ponteiros/referências. 5 8 1 4 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. L 3 1 2 X Dado armazenado Referência para o Indicador do no nó atual próximo elemento fim da lista da lista
    • Estruturas de dados dinâmicas Inserção em listas: ◦ Se a lista estiver vazia: L X 3 X ◦ Caso contrário, inserir no fim da lista:L 3 1 2 Xúltimo nó? último nó? último nó? 9 X NÃO! NÃO! SIM! novo nó
    • Estruturas de dados dinâmicas Para inserir um novo nó entre outros dois:... 4 7 ... anterior anterior.next 5 X novoNo anterior.next No novoNo = new No(5); novoNo.next = anterior.next; anterior.next = novoNo;
    • Estruturas de dados dinâmicas Remoção em listas: ◦ Para excluir um nó entre outros dois:... 1 X 9 2 ... anterior nó atual anterior.next.next anterior.next anterior.next = anterior.next.next;
    • 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 -> Modelo Palavra chave: implements Exemplo: formas Ponto e Circulo
    • Interface - Exemplopackage aula.abstracao;public interface Forma { // calcula a área public abstract double area(); // devolve o nome da figura public 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 += "nn"+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 abstratos Classes 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 abstratos Uma 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 abstratos Tentar 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 abstratos Uma 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 interface tendem 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 Forma Ponto Ponto Circulo Circulo Cilindro Cilindro Herança de Herança de Implementação Interface
    • 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: %dn", 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: %dn", 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 é %sn", formas[ind].getNome(), forma2D.getArea()); System.out.println(); } }}
    • Classes e métodos abstratos Saí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ão Elementos 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 feitascontinuamente 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! = %dn", 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 Caso básico retorna 1 return 1; // casos básicos: 0! = 1 e 1! = 1 Passo de recursão divide o problema em duas else // passo de recursão partes: com uma o método sabe como fazer; return number * factorial( number ‐ 1 );   com outra, não } // fim do método fatorial // gera saída de fatoriais para valores 0‐10Método de porção sabe o que fazer Chamada recursiva: O método portion não public void displayFactorials() { sabe como fazer; a menor versão do problema // calcula os fatoriais de 0 a 10 original for ( int counter = 0; counter <= 10; counter++ ) System.out.printf( "%d! = %dn", counter, factorial( counter ) ); } // fim do método displayFactorials } // fim da classe FactorialCalculator 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 Calcula e exibe fatoriaisSaída: Nota:0! = 1 •Omitir o caso básico ou escrever o passo de1! = 1 recursão incorretamente provoca erro!2! = 23! = 6 •Se de alguma forma isso não convirja para o caso4! = 24 básico pode causar um erro de lógica conhecido5! = 120 como recursão infinita.6! = 720 •Neste caso, as chamadas recursivas são feitas7! = 5040 continuamente até acabar a memória.8! = 403209! = 362880 •Isso é análogo ao problema de um loop infinito em10! = 3628800 uma solução iterativa (não recursiva).
    • Exemplo que utiliza recursão: Sériede 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 Dois casos básicos 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++ ) Duas chamadas recursivas System.out.printf( "Fibonacci of %d is: %dn", counter, fibonacci( counter ) ); } // fim do método displayFibonacci} // fim da classe FibonacciCalculator 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 Calcula e exibe os valores de Fibonacci Saída: Fibonacci of 0 is: 0 Fibonacci of 1 is: 1 Nota: Fibonacci of 2 is: 1 Fibonacci of 3 is: 2 Evite programas recursivos no Fibonacci of 4 is: 3 estilo Fibonacci, porque resultam Fibonacci of 5 is: 5 em uma ‘explosão’ exponencial de Fibonacci of 6 is: 8 chamadas de método. Fibonacci of 7 is: 13 Fibonacci of 8 is: 21 Fibonacci of 9 is: 34 Fibonacci of 10 is: 55
    • Conjunto de chamadas recursivas para fibonacci( 3 ).
    • Recursão e a pilha de chamadas domé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ção Qualquer 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 modorecursivo também pode ser resolvido iterativamente(não recursivamente).Uma abordagem recursiva em geral é preferidasobre uma abordagem iterativa quando a abordagemrecursiva espelha mais naturalmente o problema eresulta em um programa mais fácil de entender edepurar.Uma abordagem recursiva pode ser freqüentementeimplementada com menos linhas de código. Outrarazão de escolher uma abordagem recursiva é que umaiterativa 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; Solução iterativa utiliza a repetição controlada por contador } // 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! = %dn", counter, factorial( counter ) ); } // fim do método displayFactorials} // fim da classe FactorialCalculator
    • 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 FactorialTestSaída: Nota:0! = 1 Evite utilizar a recursão em situações que1! = 1 requerem alto desempenho. Chamadas2! = 2 recursivas levam tempo e consomem3! = 6 memória adicional.4! = 245! = 120 Ter acidentalmente um método não recursivo6! = 720 chamando a si próprio seja direta ou7! = 5040 indiretamente por outro método pode causar8! = 40320 recursão infinita.9! = 36288010! = 3628800
    • Permutações de string Permutaçõ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 n caracteres.
    • public class Permutation { // declaração recursiva do método permuteString private void permuteString(String beginningString, String endingString )   { removidos Caso básico: Combinar caracteres (beginningString) com endingString, que é // caso básico: se string a permutar tiver comprimento menor que ou igual somente um caractere // 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 Remove um caractere; localizaremos permutações for ( int i = 0; i < endingString.length(); i++ ){ os caracteres remanescentes para 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 Chamada recursiva: localizar permutações para os caracteres remanescentes e, então, reanexar os caracteres removidos // 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
    • public class PermutationTest {   public static void main( String args[] ) { Saída: Scanner scanner = new Scanner( System.in ); Permutation permutationObject = new Permutation(); math maht System.out.print( "Enter a string: " ); mtah String input = scanner.nextLine(); // recupera String a permutar mtha mhat // permuta String mhta permutationObject.permuteString( "", input ); amth amht } // fim de main atmh} // fim da classe PermutationTest athm ahmt ahtm tmah Chamada inicial ao método recursivo; ainda não há tmha caracteres removidos, assim o primeiro argumento é “” tamh tahm thma tham hmat hmta hamt hatm htma htam
    • Torres de Hanói Problema 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                               Caso básico: simplesmente exibe o movimento if ( disks == 1 ) {                                                                   System.out.printf( "n%d ‐‐> %d", sourcePeg, destinationPeg );   return;                                                          compartimento 3 como a área deMove n-1 discos do compartimento 1 Usa o para o compartimento 2 armazenamento temporário } // fim do if // passo de recursão ‐‐ move o disco para tempPeg, e depois para destinationPeg // move ( disks ‐ 1 ) discos de sourcePeg para tempPeg recursivamenteMove o último disco no compartimento 1 1, sourcePeg, tempPeg, destinationPeg );       solveTowers( disks ‐ para o compartimento 3 // move o último disco de sourcePeg para destinationPeg Usa o compartimento 1 como a área de armazenamento temporário System.out.printf( "n%d ‐‐> %d", sourcePeg, destinationPeg );     Move n-1 discos do compartimento 2 // ‐ move ( disks ‐ 1 ) discos de tempPeg para destinationPeg para o compartimento 3 solveTowers( disks ‐ 1, tempPeg, destinationPeg, sourcePeg );       } // fim do método solveTowers } // fim da classe TowersOfHanoi
    • 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 Faz a chamada inicial ao método Saída: recursivo 1 ‐‐> 3 1 ‐‐> 2 3 ‐‐> 2 1 ‐‐> 3 2 ‐‐> 1 2 ‐‐> 3 1 ‐‐> 3
    • Fractais Um 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.
    • Fractais Propriedade 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.
    • (a) (b)c) (d)(e) (f) Fractal Curva de Koch.
    • Retorno recursivo Reversã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.