Aula 6 - Recursividade David Menotti Algoritmos e Estruturas de Dados I DECOM – UFOP.
Recursividade
description
Transcript of Recursividade
![Page 1: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/1.jpg)
Recursividade
Inhaúma Neves Ferraz
Departamento de Ciência da Computação
Universidade Federal Fluminense
![Page 2: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/2.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/3.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/4.jpg)
4
Chamadas de procedimentos (não recursivos)
![Page 5: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/5.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/6.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/7.jpg)
7
Chamadas recursivas de funções
![Page 8: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/8.jpg)
8
Exemplo de Procedimentos Recursivos
Cálculo do fatorial de um inteiro
Série de Fibbonacci
Torres de Hanói
![Page 9: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/9.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/10.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/11.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/12.jpg)
Exemplo
![Page 13: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/13.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/14.jpg)
14
Exemplo de uso de pilha
x = n-1y = fact(x)fact(n) = n * y
![Page 15: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/15.jpg)
Simulação de Recursão
![Page 16: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/16.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/17.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/18.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/19.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/20.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/21.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/22.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/23.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/24.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/25.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/26.jpg)
26
Torres de Hanói
![Page 27: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/27.jpg)
27
Passagem de 4 discos do pino A para o pino C
![Page 28: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/28.jpg)
28
![Page 29: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/29.jpg)
29
Chamadas de funções (não recursivas)
![Page 30: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/30.jpg)
30
Chamadas recursivas de funções
![Page 31: Recursividade](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/31.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/32.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/33.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/34.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/35.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/36.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/37.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/38.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/39.jpg)
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](https://reader036.fdocumentos.com/reader036/viewer/2022062409/568149a2550346895db6e27b/html5/thumbnails/40.jpg)
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 */