300 likes | 411 Views
Recursividade. Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade F ederal Fluminense ferraz@ic.uff.br. Objetos e Procedimentos Recursivos. Um objeto é dito recursivo se consiste parcialmente em si mesmo ou é definido em termos de si mesmo.
E N D
Recursividade Inhaúma Neves Ferraz Departamento de Ciência da Computação Universidade Federal Fluminense ferraz@ic.uff.br
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.
Eventos que ocorrem no uso de Procedimentos Na chamada do procedimento ·Passagem dos argumentos ·Alocação e inicialização das variáveis locais ·Transferência do controle para a função (endereço de retorno) No retorno do procedimento ·Recuperação do endereço de retorno ·Liberação da área de dados ·Desvio para o endereço de retorno
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.
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
Chamadas recursivas de funções 1 2 11 3 5 10 14 8 19 17 6 12 15 18 7 16 4 9 13
Exemplo de Procedimentos Recursivos Cálculo do fatorial de um inteiro Série de Fibbonacci Torres de Hanói
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); } }
Série de Fibonacci public static int fib(int n) { // Série de Fibonacci de ordem 4 int x,y; if (n <= 1) return 1; else { x = fib(n-1); y = fib(n-2); z = fib(n-3); return x + y + z; } }
Torres de Hanói • Denote os pinos por A, B, C • Seja n o número total de discos • Numere 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: • Mova n-1 discos de A para C. Isto faz com que o disco n fique isolado no pino A • Mova o disco n de A para B • Mova n-1 discos de C para B de maneira que eles fiquem em cima do disco n
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
Exemplo de uso de pilha x = n-1 y = fact(x) fact(n) = n * y
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
Programa simulador de recursão (2) • O programa assim obtido será uma simulação não recursiva do programa recursivo. • Os laços recursivos serão substituídos por laços até obter uma pilha de recursão vazia • Dentro dos laços uma seleção múltipla (switch..case) governa os retornos e desvios do programa
Alteração inicial • Declarar uma pilha e inicializá-la como vazia • Atribuir aos dados correntes os valores adequados • Criar uma repetição até obter pilha vazia contendo uma seleção múltipla cujo parâmetro é o endereço de retorno da recursão • O primeiro caso da seleção é a condição de término da recursão
Chamadas recursivas • Quando os argumentos da chamada do procedimento forem expressões calcular o valor das expressões e atribuir estes valores aos parâmetros formais • Empilhar os parâmetros, as variáveis locais e o endereço de retorno i • Atualizar os valores dos parâmetros para o prosseguimento do programa
Substituição do return • Desempilhar os parâmetros, variáveis locais e endereço de retorno • Se o procedimento for uma função avaliar as expressões que se seguem ao return e empilhar o resultado
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
Exemplo • Será apresentado um problema clássico de recursão : • cálculo do fatorial de um inteiro
Fatorial recursivo long int fact(int n) { Long 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 */
Elemento da pilha de recursão class CFactNode { private: //atributos encapsulados long int value; long int x; long int y; short int retAddr;
Alterações iniciais long int FactSwitch(long int n) { stack<CFactNode> FactStack; long int Result; short int i; short int RetAddr; CFactNode currNode; //Empilha termo vazio para desempilhamento no final do processo FactStack.push(CFactNode(0)); //Atribui aos parâmetros e endereço de retorno os valores adequados currNode.setValue(n); currNode.setRetAddr(4); currNode.setX(0); currNode.setY(0); i = 0;
Estrutura do programa while (FactStack.size()) { switch (i) { case 0: // início do procedimento recursivo { if(currNode.getValue()== 0) //caso básico, Saída da Recursão { } else //entrada normal da recursão { } break; } //end case 0 case 1: // retorno da chamada recursiva { break; } //end case 1 default: // retorno final { return (Result); break; } //end default } //end switch } //end While
Case 0: início do procedimento case 0: // início do procedimento recursivo { if(currNode.getValue()== 0) //caso básico, Saída da Recursão { Result = 1; i = currNode.getRetAddr(); // para aonde vai currNode = FactStack.top(); FactStack.pop(); //Desempilha i = currNode.getRetAddr(); } else //entrada normal da recursão { currNode.setX(currNode.getValue() - 1) ; FactStack.push(currNode); //Empilha o currNode //O novo currNode recebe o Valor n-1 currNode.setValue(currNode.getX()); currNode.setRetAddr(1); //vai para case 1 i = 0; // chamada recursiva } break; } //end case 0
Case 1: retorno da chamada recursiva case 1: // retorno da chamada recursiva { //Parâmetro x recebe o valor de Fact(n-1); currNode.setY(Result); Result = currNode.getValue() * currNode.getY(); i= currNode.getRetAddr(); currNode = FactStack.top(); FactStack.pop(); //chamada recursiva break; } //end case 1
Case Default: retorno final default: // retorno final { return (Result); break; } //end default } //end switch } //end While }