40
Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense [email protected]

Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense [email protected]

Embed Size (px)

Citation preview

Page 1: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

Recursividade

Inhaúma Neves Ferraz

Departamento de Ciência da Computação

Universidade Federal Fluminense

[email protected]

Page 2: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

2

Objetos e Procedimentos Recursivos

Um objeto é dito recursivo se consiste parcialmente em si mesmo ou é definido em termos de si mesmo.

Procedimentos recursivos podem ser processadas por procedimentos não recursivos simulando a recursão.

Page 3: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

3

Eventos que ocorrem no uso de Procedimentos

Na chamada do procedimentoPassagem dos argumentosAlocação e inicialização das variáveis locaisTransferência do controle para a função (endereço de retorno)

  No retorno do procedimento

Recuperação do endereço de retornoLiberação da área de dadosDesvio para o endereço de retorno

 

Page 4: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

4

Chamadas de procedimentos (não recursivos)

Page 5: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

5

Implementação de procedimentos recursivos

Procedimentos recursivos só podem ser implementados em alto nível de abstração.

As máquinas não executam procedimentos recursivos.

Cabe ao “software” simular procedimentos recursivos.

Page 6: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

6

Simulação de Procedimentos Recursivos

A simulação de recursão utilizará uma pilha com os seguintes atributos gravados:Parâmetros

Variáveis

Valor da função (se for o caso)

Endereço de retorno

Page 7: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

7

Chamadas recursivas de funções

Page 8: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

8

Exemplo de Procedimentos Recursivos

Cálculo do fatorial de um inteiro

Série de Fibbonacci

Torres de Hanói

Page 9: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

9

Cálculo do fatorial de um inteiro

public class Factorial { public static void main(String[] args){ int input = Integer.parseInt(args[0]); double result = factorial(input); System.out.println(result);

} public static double factorial(int x){ if (x<0) return 0.0; else if (x==0) return 1.0; else return x*factorial(x-1); } }

Page 10: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

10

Série de Fibbonacci

public static int fib(int n){ int x,y; if (n <= 1) return 1; else { x = fib(n-1); y = fib(n-2); return x + y; }}

Page 11: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

11

Torres de HanóiDenote os pinos por A, B, C Seja n o número total de discosNumere os discos de 1 (menor, no topo da pilha) até n (maior, base da pilha)

Para mover n discos do pino A para o pino B:1. Mova n-1 discos de A para C. Isto faz com que o disco n

fique isolado no pino A 2. Mova o disco n de A para B 3. Mova n-1 discos de C para B de maneira que eles fiquem

em cima do disco n

Page 12: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

Exemplo

Page 13: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

13

Algoritmo do Fatorial

fact(n) = n * fact(n - 1) se n=o então fact(0) = 1 senão x = n-1 y = fact(x)

fact(n) = n * y fim do se

Page 14: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

14

Exemplo de uso de pilha

x = n-1y = fact(x)fact(n) = n * y

Page 15: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

Simulação de Recursão

Page 16: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

16

Programa simulador de recursão (1)

Para criar um programa que simule a recursão deve-se partir do programa recursivo e executar 3 alterações:Alteração inicial

Substituição de cada chamada recursiva por um conjunto de instruções

Substituição de cada retorno da função por um conjunto de instruções

Page 17: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

17

Programa simulador de recursão (2)

O programa assim obtido será uma simulação não recursiva do programa recursivo.

Em geral o programa assim obtido não é um programa bem estruturado e que, freqüentemente, pode ser aperfeiçoado por refinamentos subseqüentes.

Page 18: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

18

Alteração inicial

1. Declarar uma pilha e inicializá-la como vazia

2. Associar um rótulo ao primeiro comando executável

3. Atribuir aos dados correntes os valores adequados

Page 19: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

19

Chamadas recursivas

4. Criar o i-ésimo rótulo Li (ou label_i) 5. Quando os argumentos da chamada do procedimentos

forem expressões calcular o valor das expressões e atribuir estes valores aos parâmetros formais

6. Empilhar os parâmetros, as variáveis locais e o endereço de retorno i

7. Atualizar os valores dos parâmetros para o prosseguimento do programa

8. Executar um desvio incondicional para o rótulo do início do procedimento

9. Associar o rótulo criado no item (ou regra) 4 ao comando subseqüente ao desvio incondicional

Page 20: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

20

Substituição do return

10. Retornar se a pilha estiver vazia

11. Desempilhar os parâmetros, variáveis locais e endereço de retorno

12. Se o procedimento for uma função avaliar as expressões que se seguem ao return e empilhar o resultado

13. Executar um desvio condicional para o rótulo especificado no endereço de retorno corrente

Page 21: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

21

Modelos de geração de programas não recursivos simulando programas recursivos

Modelo de alteração inicial

Modelo de chamada recursiva

Modelo de retorno de chamada recursiva

Page 22: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

22

Alteração Inicial

/* Passo 1: Pilha vazia */s.top = MENOS_UM;/* inicialização de área vazia */currarea.x = 0; /* por exemplo */currarea.y = ‘’; /* por exemplo */currarea.retaddr = 0; /* empilhar a área vazia */push(&s,&currarea); /* Passo 3: Atribuir aos parametros e endereço de

retorno os valores adequados */currarea.param = n; /* por exemplo */currarea.retaddr = 1; /* 1 para retornar a main. 2 para

recursão */ start : /* Passo 2: associar rótulo inicial ao primeiro

comando executável */

Page 23: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

23

Chamada Recursiva

/* simulação de chamada recursiva *//* Passo 6: empilhamento */push(&s,&currarea);/* Passo 7: atualização dos valores dos parâmetros */currarea.x = ...; /* por exemplo */..currarea.retaddr = i; /* Passo 8: desvio incondicional para o rótulo inicial */goto start; label_i : /* Passos 4 e 9: rótulo associado ao comando subseqüente ao desvio */

Page 24: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

24

Retorno de função

/* simulação de return *//* Passo 11: desempilhar */ i = currarea.retaddr; pop(&s,&currarea);/* Passo 13: desvio condicional para o endereço de retorno */switch (i) { case 1 : goto label1; /* tantos casos quantos forem as chamadas recursivas + 1 */.. case m : goto label2; } /* end switch */} /* end if (currarea.param == 0) */

Page 25: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

25

Exemplos

Serão apresentados dois problemas clássicos de recursão : cálculo do fatorial de um inteiro problema conhecido como Torres de Hanói

Page 26: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

26

Torres de Hanói

Page 27: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

27

Passagem de 4 discos do pino A para o pino C

Page 28: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

28

Page 29: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

29

Chamadas de funções (não recursivas)

Page 30: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

30

Chamadas recursivas de funções

Page 31: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

31

Fatorial recursivolong int fact(int n){int x;long int y;if (n < 0) { printf("parâmetro negativo: %d\n",n); exit(1); } /* end if */ if (n == 0) return (1); x = n-1;y = fact(x);return(n*y);} /* end fact */

Page 32: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

32

Simulação da recursão (1)

long int simfact1(int n){// Simulação de fatorialstruct dataarea currarea;short int i;long int result;s.top = MENOS_UM;/* inicialização de área vazia */currarea.param = 0;currarea.x = 0;currarea.y = 0;currarea.retaddr = 0; /* empilhar a área vazia */if (push(&s,&currarea) == MENOS_DOIS) { printf("Estouro de pilha\n"); exit(1); } /* end if *//* Atribuir ao parametro e endereço de retorno os valores adequados */currarea.param = n;currarea.retaddr = 1; /* 1 para retornar a main. 2 para recursão */

Page 33: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

33

Simulação da recursão (2)

start : /*inicio da rotina de simulação de fatorial */ if (currarea.param == 0) { /* fact(0) */

/* simulação de return */ result = 1; /* fact(0) == 1; */ i = currarea.retaddr; if (pop(&s,&currarea) == MENOS_UM) { printf("Pilha vazia\n"); } /* end if */switch (i) { case 1 : goto label1; case 2 : goto label2; } /* end switch */} /* end if (currarea.param == 0) */

  /* currarea.param != 0 */currarea.x = currarea.param - 1;/* simulação de chamada recursiva */if (push(&s,&currarea) == MENOS_DOIS) { printf("Estouro de pilha\n"); exit(1); } /* end if */currarea.param = currarea.x;currarea.retaddr = 2;goto start; /* chamada recursiva */

Page 34: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

34

Simulação da recursão (3)

label2 : /* ponto de retorno da chamada recursiva */ /* atribui-se o valor retornado a cuurarea.y */ currarea.y = result; /* simulação de return(n*y) */ result = currarea.param * currarea.y; i = currarea.retaddr; /* voltar ao ambiente original */ if (pop(&s,&currarea) == MENOS_UM) { printf("Pilha vazia\n"); } /* end if */switch (i) { case 1 : goto label1; case 2 : goto label2; } /* end switch */

label1 : /* ponto de retorno ao programa principal */ return (result);

} /* end simfact1 */

Page 35: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

35

O programa simulador obtido

O programa simulador obtido ( fat_nr01) não tem uma boa estrutura.

Ele pode, e deve, ser aperfeiçoado por refinamentos subseqüentes.

Inicialmente será criado o programa fat_nr02.

Page 36: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

36

Passagem de fat_nr01 para fat_nr02

O fatorial corrente y e o valor corrente x podem ser globais não necessitando ser empilhados.

Como só há um endereço de retorno de chamada recursiva, só há um endereço de retorno, pois o retorno ao programa chamador é testado pela condição de pilha vazia. Portanto não é preciso empilhar endereços de retorno usando desvio incondicional

Page 37: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

37

Passagem de fat_nr02 para fat_nr03

switch(pop(&s,&currarea)){ aparece duas vezes e agrupando estas ocorrências pode-se simplificar o algoritmo

x e currparam nunca são usadas simultaneamente e podem ser uma só variável x

Page 38: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

38

Passagem de fat_nr03 para fat_nr04

O laço criado pelo teste inicial e terminado por goto start pode ser substituído por um laço while

O laço iniciado por label2 e terminado por switch(pop(... pode ser substituído por outro laço while

Page 39: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

39

Passagem de fat_nr04 para fat_nr05

O primeiro laço while empilha 1 a n, sendo 1 no topo

O segundo laço while multiplica o resultado corrente pelo topo da pilha

Sabendo disso não é preciso nem empilhar nada

Page 40: Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br

40

Algoritmo recursivo das Torres de Hanóivoid towers(int n, char from, char to, char aux){/* Caso haja um só disco, mova-o e retorne */if (n == 1) { printf("Mover disco 1 do pino %c para o pino %c\n",

from, to); return; } /* end if *//* Mover os n-1 discos superiores de A para B usando C como auxiliar */towers(n-1,from,aux,to);/* Mover o disco restante de A para C */ printf("Mover disco %d do pino %c para o pino %c\n",

n, from, to);/* Mover os n-1 discos de B para C usando A como auxiliar */towers(n-1,aux,to,from);return;} /* end towers */