Dinamicas

80
Variáveis Dinâmicas, Abstração e Recursividade Técnicas de Programação Prof. Iális Cavalcante Engenharia da Computação 2011.1

Transcript of Dinamicas

Page 1: Dinamicas

Variáveis Dinâmicas, Abstração e RecursividadeTécnicas de ProgramaçãoProf. Iális CavalcanteEngenharia da Computação2011.1

Page 2: Dinamicas

VARIÁVEIS DINÂMICAS

Page 3: Dinamicas

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

Page 4: Dinamicas

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)

Page 5: Dinamicas

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

Page 6: Dinamicas

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

Page 7: Dinamicas

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.

Page 8: Dinamicas

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.

Page 9: Dinamicas

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).

Page 10: Dinamicas

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;

}

Page 11: Dinamicas

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(){}

}

Page 12: Dinamicas

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;

Page 13: Dinamicas

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;

Page 14: Dinamicas

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).

Page 15: Dinamicas

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

Page 16: Dinamicas

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

Page 17: Dinamicas

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?

Page 18: Dinamicas

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;

Page 19: Dinamicas

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

Page 20: Dinamicas

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.

Page 21: Dinamicas

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.

Page 22: Dinamicas

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 () { }

}

Page 23: Dinamicas

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.

Page 24: Dinamicas

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

Page 25: Dinamicas

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ó

Page 26: Dinamicas

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

Page 27: Dinamicas

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

Page 28: Dinamicas

ABSTRAÇÃO

Page 29: Dinamicas

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.

Page 30: Dinamicas

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.

Page 31: Dinamicas

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.

Page 32: Dinamicas

Interface

Interface -> ModeloPalavra chave: implementsExemplo: formas Ponto e Circulo

Page 33: Dinamicas

Interface - Exemplo

package aula.abstracao;public interface Forma {

// calcula a áreapublic abstract double area();// devolve o nome da figurapublic abstract String getNome();

}

Page 34: Dinamicas

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

}

Page 35: Dinamicas

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

}

Page 36: Dinamicas

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;

(...)

Page 37: Dinamicas

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);

}

}

Page 38: Dinamicas

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

Page 39: Dinamicas

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.

Page 40: Dinamicas

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.

Page 41: Dinamicas

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.

Page 42: Dinamicas

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.

Page 43: Dinamicas

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.

Page 44: Dinamicas

Classes e métodos abstratos

Ponto

Circulo

Cilindro

Forma

Ponto

Circulo

Cilindro

Herança deImplementação

Herança deInterface

Page 45: Dinamicas

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

}

Page 46: Dinamicas

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

}

Page 47: Dinamicas

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());

}

}

Page 48: Dinamicas

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());

}

}

Page 49: Dinamicas

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();

}

}

}

Page 50: Dinamicas

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

Page 51: Dinamicas

RECURSIVIDADE

Page 52: Dinamicas

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.

Page 53: Dinamicas

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.

Page 54: Dinamicas

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.

Page 55: Dinamicas

Avaliação recursiva de 5!.

Page 56: Dinamicas

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

Page 57: Dinamicas

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

Page 58: Dinamicas

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).

Page 59: Dinamicas

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.

Page 60: Dinamicas

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

Page 61: Dinamicas

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.

Page 62: Dinamicas

Conjunto de chamadas recursivas para fibonacci( 3 ).

Page 63: Dinamicas

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.

Page 64: Dinamicas

Chamadas do método feitas dentro da chamada fibonacci( 3 ).

Page 65: Dinamicas

Chamadas do método na pilha de execução do programa.

Page 66: Dinamicas

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.

Page 67: Dinamicas

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.

Page 68: Dinamicas

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

Page 69: Dinamicas

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.

Page 70: Dinamicas

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.

Page 71: Dinamicas

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

Page 72: Dinamicas

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

Page 73: Dinamicas

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.

Page 74: Dinamicas

Torres de Hanói para o caso com quatro discos.

Page 75: Dinamicas

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

Page 76: Dinamicas

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

Page 77: Dinamicas

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.

Page 78: Dinamicas

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.

Page 79: Dinamicas

Fractal Curva de Koch.

(a) (b)

c) (d)

(e) (f)

Page 80: Dinamicas

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.