Recursividade. Aula 9



Documentos relacionados
Nível da Arquitetura do Conjunto das Instruções

Programação Estruturada. Programação Estruturada. Idéias Básicas da Programação Estruturada

A Torre de Hanói e o Princípio da Indução Matemática

Capítulo 8. CICLOS. Tabela 8.1 Programa8a.f90.

Programação Funcional. Aula 5. Funções Recursivas. José Romildo Malaquias. Departamento de Computação Universidade Federal de Ouro Preto 2011.

Faculdade de Computação

INTRODUÇÃO À LINGUAGEM C++

Linguagens de Programação Aula 10

P r o g r a m a ç ã o d e C o m p u t a d o r e s 1 o S e m P r o f. A n d r é A m a r a n t e L u i z L A B 5 tag %2d while printf PE1:

Algoritmos e Estruturas de Dados I 01/2013. Estruturas Condicionais e de Repetição (parte 2) Pedro O.S. Vaz de Melo

Programação: Estruturas de seleção

Algoritmo e Técnica de Programação - Linguagem C

Introdução à Programação. Recursão

9 Comandos condicionais

compreender a importância de cada estrutura de controle disponível na Linguagem C;

5 Apresentando a linguagem C

A Pilha. Aula 02. DPEE 1038 Estrutura de Dados para Automação Curso de Engenharia de Controle e Automação Universidade Federal de Santa Maria

LÓGICA DE PROGRAMAÇÃO. PROFª. M.Sc. JULIANA H Q BENACCHIO

Introdução à Programação. Armazenamento de Grande Quantidade de Informação Usando Vetores

Implementando uma Classe e Criando Objetos a partir dela

Conceitos básicos da linguagem C

Linguagem de Programação JAVA. Técnico em Informática Professora Michelle Nery

Linguagem C: variáveis, operadores, entrada/saída. Prof. Críston Algoritmos e Programação

JavaScript (ou JScript)

Estrutura de Dados Básica

Algoritmo Iterativo. Dilema do Martelo x Edifício. O Martelo. O Edifício 01/06/2014. Dilema das ações x declarações

Computação II Orientação a Objetos

Filas. A ordem de saída corresponde diretamente à ordem de entrada dos elementos. Fila de caixa bancário

3. INTRODUÇÃO À LINGUAGEM C 3.1. CONCEITOS BÁSICOS. Lógica de Programação

Capítulo 12. SUB-ROTINAS

Tabela de Símbolos. Análise Semântica A Tabela de Símbolos. Principais Operações. Estrutura da Tabela de Símbolos. Declarações 11/6/2008

Algoritmos e Programação

Aula 3 Alocação Dinâmica

BACHARELADO EM SISTEMAS DE INFORMAÇÃO EaD UAB/UFSCar Sistemas de Informação - prof. Dr. Hélio Crestana Guardia

MODELAGEM E SIMULAÇÃO

Desmistificando o Programa de Computador

Introdução a Computação

Estruturas de Repetição

15 a Aula Subprogramação /Subalgoritmos Função e Procedimento

AULA 1: PARADIGMAS DE PROGRAMAÇÃO

TÉCNICAS DE PROGRAMAÇÃO

Algoritmos e Estruturas de Dados I. Universidade Federal de São João del-rei Pedro Mitsuo Shiroma Sala 119 Bloco 3

Convertendo Algoritmos para a Linguagem C

Regras Métodos Identificadores Variáveis Constantes Tipos de dados Comandos de atribuição Operadores aritméticos, relacionais e lógicos

- Aulas 57, 58, 59 e 60 - Técnicas de programação. Funções

Algoritmos e Programação Estruturada

Comandos de repetição while

José Romildo Malaquias

9.1.2 Laços Controlados por Entrada: Contador

ARQUITECTURA DE COMPUTADORES CAPÍTULO II AULA X

7. Estrutura de Decisão

Algoritmos e Programação II. Sobrecarga

Variáveis e Comandos de Atribuição

Java Como Programar, 8/E

INF 1010 Estruturas de Dados Avançadas

Organização de Computadores Software

Lógica para Computação

Capítulo 2: Introdução à Linguagem C

Fração como porcentagem. Sexto Ano do Ensino Fundamental. Autor: Prof. Francisco Bruno Holanda Revisor: Prof. Antonio Caminha M.

Lista restrita onde as operações de inserção e retirada são feitas nas extremidades. Deque (fila de final duplo).

Plano de Aula. if(condição) { bloco de comandos; } else { bloco de comandos2; }

Introdução a Teoria das Filas

Aula 12: Funções. Pré-requisitos: Todas as aulas anteriores deste módulo. 1. Aproveitando Códigos no Programa

INF 1005 Programação I

Introdução a Programação. Ponteiros e Strings, Alocação Dinâmica

Linguagem C Tipos de Dados. void; escalares; sizeof Vectores; strings em C Estruturas Introdução ao pré-processador

Sumário. Administração de Banco de dados Módulo 12. Ilustração Backup-Recovery. Recuperação (Recovery) - Definição

INTRODUÇÃO À PROGRAMAÇÃO

GFM015 Introdução à Computação Linguagem C / Introdução à Modularização de Programas (uso de subprogramas)

Algoritmos Estruturas Seqüenciais. José Gustavo de Souza Paiva

I Semana de Software Livre da USP Dojo C

CADERNOS DE INFORMÁTICA Nº 1. Fundamentos de Informática I - Word Sumário

Lógica para a Programação - 1º semestre AULA 01 Prof. André Moraes

LINGUAGEM C. Estrutura básica de um programa

ITENS FUNDAMENTAIS. Profª Angélica da Silva Nunes

DALUA: BIBLIOTECA PARA APLICAÇÕES DISTRIBUÍDAS

Introdução. A Informação e sua Representação (Parte II) Universidade Federal de Campina Grande. Unidade Acadêmica de Sistemas e Computação

Programação em papel quadriculado

Analise o código abaixo:

Estruturas de Dados Aula 15: Árvores 17/05/2011

Busca em Memória. Secundária

Processos. Estados principais de um Processo: Contexto de um Processo. Nível de um Processo.

Análise de Arredondamento em Ponto Flutuante

Programação Engenharia Informática (11543) 1º ano, 1º semestre Tecnologias e Sistemas de Informação (6619) 1º ano, 1º semestre

ALGORITMOS E FLUXOGRAMAS

c. Técnica de Estrutura de Controle Teste do Caminho Básico

Lista de Exercícios 3 Estruturas de Controle Profa Susana M Iglesias

10/02/2015. Introdução. Podemos classificar os tipos de dados a serem processados em dados e instruções Dados: Algoritmos e Lógica de Programação

Divisão e Conquista. Túlio Toffolo Marco Antônio Carvalho marco.opt@gmail.com. BCC402 Aula 08 Algoritmos e Programação Avançada

Linguagem C. Programação Estruturada. Fundamentos da Linguagem. Prof. Luis Nícolas de Amorim Trigo

Trabalho 3: Agenda de Tarefas

natureza do projeto e da aplicação métodos e ferramentas a serem usados controles e produtos que precisam ser entregues

INTRODUÇÃO A ROBÓTICA

TRABALHO DE PROGRAMAÇÃO FUNCIONAL LINGUAGEM DE PROGRAMAÇÃO I

Linguagem de Montagem 2. Operações e Operandos

Capítulo 2. VARIÁVEIS DO TIPO INTEIRO

Introdução à Engenharia de Computação

Transcrição:

Recursividade Aula 9

Em matemática vários objetos são definidos apresentando-se um processo que os produz. Ex PI (circunferência/diâmetro) Outra definição de um objeto por um processo é o fatorial de um número

Fatorial(n) ou n! = n*(n-1)*(n-2)...(2)*1 se n >0 =1 se n==0 Se formulamos: 0! = 0 1! = 1 2! = 2 * 1 3! = 3 * 2 * 1 4! = 4 * 3 * 2 * 1 Não é possível listar a fórmula para fatorial de cada inteiro

Para evitar qualquer abreviatura e um cjto infinito de definições poderemos apresentar um algoritmo que aceite um número inteiro n e retorne n! prod = 1; for (x = n; x > 0; x--) prod *= x; return prod; ALGORITMO ITERATIVO: Requer de repetição explícita até uma condição ser satisfeita.

Um algoritmo pode ser considerado Um programa ideal sem quaisquer limitações práticas de um computador real e portanto pode ser usado para definir uma função matemática, entretanto uma função de C não serve como definição matemática da função fatorial por causa de limitações como precisão e tamanho finito de uma máquina real.

Examinemos detalhadamente a definição de n! que lista uma fórmula separada para cada valor de n Ex 4! = 4 * 3 * 2 * 1 isso é igual a 4 * 3! Para todo n>0 verificamos que n! = n* (n-1)! Podemos definir: 0! = 1 1! = 1 * 0! 2! = 2 * 1! 3! = 3 * 2! 4! = 4 * 3! 5! = 5 * 4!

Se empregamos uma notação matemática temos que n! = 1 se n == 0 n! = n * (n - 1)! se n >0 Definição de uma função em termos de se mesma, aparentemente circular. Método conciso de escrever um número infinito de equações necessárias para definir n! Definição RECURSIVA

A recursividade pode ser utilizada quando um problema puder ser definido em termos de si próprio. Por exemplo, quando um objeto é colocado entre dois espelhos planos paralelos e frente a frente surge uma imagem recursiva, porque a imagem do objeto refletida num espelho passa a ser o objeto a ser refletido no outro espelho e, assim, sucessivamente. Uma função recursiva chama ela mesma, mas com outros parâmetros.

Algoritmos Recursivos A idéia básica de um algoritmo recursivo consiste em diminuir sucessivamente o problema em um problema menor ou mais simples, até que o tamanho ou a simplicidade do problema reduzido permita resolvê-lo de forma direta, sem recorrer a si mesmo. Quando isso ocorre, diz que o algoritmo atingiu uma condição de parada, a qual deve estar presente em pelo menos um local dentro algoritmo. Sem esta condição o algoritmo não pára de chamar a si mesmo, até estourar a capacidade da pilha de execução, o que geralmente causa efeitos colaterais e até mesmo o término indesejável do programa.

Componentes de um algoritmo recursivo Condição de parada, quando a parte do problema pode ser resolvida diretamente, sem chamar de novo a função recursiva. Outros comandos que resolvem uma parte do problema (chamando novamente a função recursiva);

Algoritmos Recursivos f1(..)......... chama f1(..)...... fim f1(..)...... chama f1(..)...... f1(..)......... condição de parada!

1. 5! = 5 * 4! 2. 4! = 4 * 3! 3. 3! = 3 * 2! 4. 2! = 2 * 1! 5. 1! = 1 * 0! 6. 0! = 1 Cada caso é reduzido a um caso mais simples até chegarmos ao caso 0! Que é definido imediatamente como 1

Se voltarmos 6 0! = 1 5 1! = 1 * 0! = 1 * 1 = 1 4 2! = 2 * 1! = 2 * 1 = 2 3 3! = 3 * 2! = 3 * 2 = 6 2 4! = 4 * 3! = 4 * 6 = 24 1 5! = 5 * 4! = 5 * 24 = 120

Se levamos esse processo a um algoritmos teremos if (n == 0) fact = 1; else { x = n -1; ache o valor de x!. Chame-o de y; fact = n * y;} Definição recursiva do processo do cálculo do fatorial

int main(void) { int NUMERO, RESULTADO; scanf("%d", &NUMERO); RESULTADO = FAT(NUMERO); printf("%d\n", RESULTADO); } int FAT(int N) { int AUX; if(n == 0) // condição de parada return 1; AUX = N * FAT(N - 1); return AUX; } LEMBRE-SE!! N é variável local da função FAT. É melhor a definição recursiva de fatorial?

Programa principal: main NUMERO = 2 RESULTADO = FAT(2) Função FAT: PRIMEIRA CHAMADA N = 2 AUX = 2 * FAT(1) 1

Função FAT: PRIMEIRA CHAMADA Função FAT: SEGUNDA CHAMADA N = 2 AUX = 2 * FAT(1) N = 1 AUX = 1 * FAT(0) 1 2

Função FAT: SEGUNDA CHAMADA Função FAT: TERCEIRA CHAMADA N = 1 AUX = 1 * FAT(0) N = 0 condição de parada atingida!!! if (N = = 0) return 1; 2 3

Função FAT: SEGUNDA CHAMADA Função FAT: TERCEIRA CHAMADA N = 1 AUX = 1 * FAT(0) AUX = 1 1 N = 0 condição de parada atingida!!! if (N = = 0) return 1; 2 3

Função FAT: PRIMEIRA CHAMADA Função FAT: SEGUNDA CHAMADA N = 2 AUX = 2 * FAT(1) 1 N = 1 AUX = 1 * FAT(0) 1 AUX = 2 AUX = 1 1 2

Programa principal: main Função FAT: PRIMEIRA CHAMADA NUMERO = 2 RESULTADO = FAT(2) 2 N = 2 AUX = 2 * FAT(1) 2 RESULTADO = 2 AUX = 2 1

Problemas associados a recursividade Recursões que não terminam!!! Um requisito fundamental é que a chamada recursiva esteja sujeita à uma condição booleana que em um determinado momento irá se tornar falsa e não mais ativará a recursão (condição de parada!). Um subprograma recursivo deve ter obrigatoriamente uma condição que controla sua execução ou término, sob pena de produzir uma computação interminável.

Multiplicação de números naturais Outro exemplo de definição recursiva O produto A*B em que a e b são inteiros positivos pode ser definido como A somado a se mesmo b vezes. Essa definição é ITERATIVA Definição recursiva a * b = a se b == 1 a * b = a * (b - 1) + a se b > 1

Exemplo: 6 * 3 = 6 * 2 + 6 = 6 * 1 + 6 + 6 = 6 + 6 + 6 = 18 Exercício: Converter num algoritmo recursivo. Observe padrão de definições recursivas (caso simples e avaliação de casos mais simples) Por que não podemos usar definições como?? n! = (n + 1)! / (n + 1) a * b = a * (b + 1) - a

A seqüência de Fibonacci Seqüência de inteiros do tipo 0, 1, 2, 2, 3, 5, 8, 13, 21, 34 Cada elemento da seqüência é a soma dos dois elementos anteriores. Se permitimos que fib(0) = 0 e fib(1) = 1 fib(n) = n se n == 0 ou n == 1 fib(n) = fib(n-2) + fib(n-1) se n >= 2 Que diferencia a definição da seqüência de Fibonacci da do fatorial e da multiplicação dos números naturais??

A seqüência de Fibonacci Note que: fib(6) = fib(5) + fib(4) = fib(4) + fib(3) + fib(3) + fib(2) = fib(3) + fib(2) + fib(3) + fib(3) + fib(2) E assim por diante. Que tem de errado?????? Seria mais eficiente lembrar quanto é fib(3) na primeira vez que ele for chamado

Solução iterativa: if (n <= 1) return(n); lofib = 0; hifib = 1; for (i = 2; i <= n; i++) { x = lofib; lofib = hifib; hifib = x + lofib; } return hifib;

Solução recursiva

FIB(5)

FIB(5) FIB(4) FIB(3)

FIB(5) FIB(4) FIB(3) FIB(3) FIB(2)

FIB(5) FIB(4) FIB(3) FIB(3) FIB(2) FIB(2) FIB(1)

FIB(5) FIB(4) FIB(3) FIB(3) FIB(2) FIB(2) FIB(1) FIB(2) FIB(1)

FIB(5) FIB(4) FIB(3) FIB(3) FIB(2) FIB(2) FIB(1) 1 FIB(1)

FIB(5) FIB(4) FIB(3) FIB(3) FIB(2) FIB(2) FIB(1) 1 1

FIB(5) FIB(4) FIB(3) 2 FIB(2) FIB(2) FIB(1) 1 1

FIB(5) FIB(4) FIB(3) 2 1 FIB(2) FIB(1) 1 1

FIB(5) FIB(4) FIB(3) 2 1 1 FIB(1) 1 1

FIB(5) FIB(4) FIB(3) 2 1 1 1 1 1

FIB(5) 3 FIB(3) 2 1 1 1 1 1

FIB(5) 3 2 2 1 1 1 1 1

5 3 2 2 1 1 1 Resposta: O 5º termo da série é 5. 1 1

Torres de Hanoi Problema criado pelo matemático francês Edouard Lucas, em 1883; 3 torres; x discos de vários tamanhos na primeira torre; Objetivo: transportar os discos, 1 a 1, para a terceira torre; Regras: nunca colocar um disco maior sobre um disco menor; pode-se mover um único disco por vez; nunca colocar um disco noutro lugar que não numa das três hastes.

Torres de Hanoi

Torres de Hanoi Lucas também criou uma lenda que dizia que em Benares, durante o reinado do imperador Fo Hi, existia um templo que marcaria o centro do universo. Dentro deste templo, alguns monges moviam discos de ouro entre 3 torres de diamante. Deus colocou 64 discos de ouro em uma das torres na hora da criação do universo. Diz-se que, quando os monges completarem a tarefa de transportar todos os discos para a terceira torre, o universo terminará. (como vai levar pelo menos 2 64-1 movimentos para completar a tarefa, estamos a salvo por enquanto. Assumindo que os monges realizem 1 movimento por segundo, e não cometam erros, eles irão levar um total de 585,000,000,000 anos.)

Como resolver? Sejam 4 discos na torre 1. Problema principal: Mover 4 discos da torre 1 para a torre 3.

Recursão! Mover 4 discos da torre 1 para a torre 3: mover 3 discos da torre 1 para a torre 2; mover 1 disco da torre 1 para a torre 3; mover 3 discos da torre 2 para a torre 3.

Recursão! Mover 4 discos da torre 1 para a torre 3: mover 3 discos da torre 1 para a torre 2; mover 1 disco da torre 1 para a torre 3; mover 3 discos da torre 2 para a torre 3.

Recursão! Mover 4 discos da torre 1 para a torre 3: mover 3 discos da torre 1 para a torre 2; mover 1 disco da torre 1 para a torre 3; mover 3 discos da torre 2 para a torre 3.

Recursão! Mover 4 discos da torre 1 para a torre 3: mover 3 discos da torre 1 para a torre 2; mover 1 disco da torre 1 para a torre 3; mover 3 discos da torre 2 para a torre 3.

Divisão do problema Logo o problema principal: Mover 4 discos da torre 1 para a torre 3 Se transforma em um problema menor: mover 3 discos da torre 1 para a torre 2; mover 1 disco da torre 1 para a torre 3; mover 3 discos da torre 2 para a torre 3. Mas, como mover 3 discos?

Divisão do problema Mover 3 discos da torre 1 para a torre 2: mover 2 discos da torre 1 para a torre 3; mover 1 disco da torre 1 para a torre 2; mover 2 discos da torre 3 para a torre 2.

Divisão do problema Mover 3 discos da torre 1 para a torre 2: mover 2 discos da torre 1 para a torre 3; mover 1 disco da torre 1 para a torre 2; mover 2 discos da torre 3 para a torre 2.

Divisão do problema Mover 3 discos da torre 1 para a torre 2: mover 2 discos da torre 1 para a torre 3; mover 1 disco da torre 1 para a torre 2; mover 2 discos da torre 3 para a torre 2.

Divisão do problema Mover 3 discos da torre 1 para a torre 2: mover 2 discos da torre 1 para a torre 3; mover 1 disco da torre 1 para a torre 2; mover 2 discos da torre 3 para a torre 2.

Algoritmo Mover x discos, da torre a para a torre b: mover (x-1) discos, da torre a para a torre c mover 1 disco da torre a para a torre b mover (x-1) discos, da torre c para a torre b Função de parada: Se o número de discos = 1, move direto.

Observações Sejam 3 torres, com os números 1, 2 e 3. Dadas 2 torres, como descobrir qual a terceira? Isto é, dadas as torres 1 e 3, como descobrir que a outra torre é a 2? Dadas as torres 2 e 3, como descobrir que a outra torre é a 1?

Observação Note: 1 + 2 + 3 = 6 Logo: A outra torre é 6 - (soma das torres indicadas) Exemplos: torres 1 e 2 Outra torre: 6 - (1 + 2) = 6-3 = 3 torres 2 e 3 Outra torre: 6 - (2 + 3) = 6-5 = 1

Solução void HANOI(int ND, int DE, int PARA) { int OUTRA_TORRE = 6 - (DE + PARA); if(nd == 1) { printf("mover disco da torre %d para a torre %d.\n", DE, PARA); return; } } HANOI(ND-1, DE, OUTRA_TORRE); HANOI(1, DE, PARA); HANOI(ND-1, OUTRA_TORRE, PARA); return;

Solução Digite o numero de discos: 4 Mover disco da torre 1 para a torre 2. Mover disco da torre 1 para a torre 3. Mover disco da torre 2 para a torre 3. Mover disco da torre 1 para a torre 2. Mover disco da torre 3 para a torre 1. Mover disco da torre 3 para a torre 2. Mover disco da torre 1 para a torre 2. Mover disco da torre 1 para a torre 3. Mover disco da torre 2 para a torre 3. Mover disco da torre 2 para a torre 1. Mover disco da torre 3 para a torre 1. Mover disco da torre 2 para a torre 3. Mover disco da torre 1 para a torre 2. Mover disco da torre 1 para a torre 3. Mover disco da torre 2 para a torre 3. Pressione qualquer tecla para continuar...

Mover disco da torre 1 para a torre 2.

Mover disco da torre 1 para a torre 3.

Mover disco da torre 2 para a torre 3.

Mover disco da torre 1 para a torre 2.

Mover disco da torre 3 para a torre 1.

Mover disco da torre 3 para a torre 2.

Mover disco da torre 1 para a torre 2.

Mover disco da torre 1 para a torre 3.

Mover disco da torre 2 para a torre 3.

Mover disco da torre 2 para a torre 1.

Mover disco da torre 3 para a torre 1.

Mover disco da torre 2 para a torre 3.

Mover disco da torre 1 para a torre 2.

Mover disco da torre 1 para a torre 3.

Existem linguagens de programação que não suportam recursividade como FORTAM, COBOL e muitos linguagens de máquina Porem soluções recursivas podem ser simuladas se entendermos o conceito e funcionamento da recursividade Não é raro que um programador consiga enunciar uma solução recursiva para um problema, as vezes a solução recursiva é a mais natural e simples porem as soluções recursivas são com freqüência mais dispendiosas que a solução não recursiva.

Em geral uma solução não recursiva de um programa executará com mais eficiência em termos de espaço e tempo, isso acontece porque a solução não recursiva evita o trabalho extra de entrar e sair de um bloco e o empilhamento de desnecessário de variáveis Contudo verificaremos que a solução recursiva é as vezes o método mais natural e lógico de desenvolver como é o caso das torres de Hanoi e menos propenso a erros Conflito EFICIENCIA DA MAQUINA X EFICIENCIA DO PROGRAMADOR Nestes casos versões simuladas dos casos recursivos é uma excelente solução

Que acontece quando uma função é chamada?? 1. Passar argumentos: Para um parâmetro em C uma copia é criada localmente dentro da função e quaisquer mudança e feita nessa copia local. O original não é alterado 2. Alocar e inicializar variáveis locais: Depois que os argumentos forem passados as variáveis locais da função serão alocadas. As diretamente declaradas na função e as temporais 3. Transferir o controle para a função: Deve ser passado o endereço de retorno como parâmetro

Quando retorna que acontece? 1. O endereço de retorno é recuperado e armazenado num logar seguro 2. A área de dados da função é liberada 3. Usa-se um desvio para o endereço de retorno salvo anteriormente, deve também salvar se os valores de retorno para que o chamador possa recuperar esse valor.

Programa principal Chamada de b Procedimento b Endereço de retorno Chamada de c Procedimento c Endereço de retorno Chamada de d Procedimento d Endereço de retorno Programa principal Chamada de b Procedimento b Endereço de retorno Chamada de c Procedimento c Endereço de retorno Chamada de d controle controle

Observe que a seqüência de endereços de retorno forma uma pilha isto é o mais recente endereço de retorno a ser incluído na cadeia é o primeiro a ser removido. Em qualquer ponto só poderemos acessar o endereço de retorno a partir da função atualmente em execução que representa o topo da pilha. Quando uma pilha é esvaziada (isto é quando a função retornar) será revelado um novo topo dentro da rotina de chamadas. Chamar uma função tem o efeito de incluir um elemento numa pilha e retornar da função de eliminá-lo

Cada vez que uma função recursiva chama a si mesma uma área de dados totalmente nova para essa chamada precisa ser alocada. Essa área contem todos os parâmetros variáveis locais temporárias e endereços de retorno. Todo retorno acareia a liberação da atual área de dados. Sugere-se o uso de uma pilha

Poderemos usar uma estrutura do tipo #define MAXSTACK 50; struct stack{ int top; struct dataarea item[maxstack] }

Passos da conversão Desenvolver caso recursivo Desenvolver simulação com todas as pilhas e temporários Eliminar todas as pilhas e variáveis supérfluas Quando uma pilha não pode ser eliminada da versão não recursiva e quando a versão recursiva não contem nenhum dos parâmetros adicionais o variáveis locais, a versão recursiva pode ser tão o mais veloz que a não recursiva sob um compilador eficiente. Exemplo Torres de Hanoi

O fatorial que não precisa pilha na implementação não recursiva e a geração de números de fibonacci onde temos uma chamada desnecessária e também não precisa de pilha a solução recursiva deve ser evitada na pratica Até onde uma solução recursiva pode ser transformada em direta dependerá do problema e a engenhosidade do programador

Simulação de Recursividade struct stack { int top; struct dataarea item[maxstack]; }; void popsub(struct stack *s, struct dataarea *a){ *a = s->item[s->top]; s->top--; } void push(struct stack *s, struct dataarea *a){ s->top++; s->item[s->top] = *a; }

Simulação de Recursividade int fact(int n){ int x, y; if (n==0) return(1); x = n-1; y = fact(x); return (n * y); } Ponto 1 para retornar (labe2 y = result;) Ponto 2 para retornar (label1: return(result);)

Simulação de Recursividade struct dataarea{ int param; int x; //parametro simulado (n) //variaveis atuais da chamada long int y; short int retaddr; //endereço de retorno (1 ou 2) }; switch(i){ case 1: goto label1; //retorno ao prg principal case 2: goto label2; //simulando à atribuição do valor //retornado à variavel y na execução //anterior de fact }

Simulação de Recursividade //retorno a partir de fact result = valor a ser retornado; i = currarea.retaddr; popsub(&s, &currarea); switch(i){ case 1: goto label1; case 2: goto label2; }

Simulação de Recursividade //chamada introduz a atual área na pilha //atualiza os valores dos parâmetros e //transfere o controle para o inicio da rotina push(&s, &currarea); currarea.param = currarea.x; currarea.retaddr = 2; goto start;

long int simfact(int n){ struct dataarea currarea; struct stack s; short i; long int result; s.top = -1; currarea.param = 0; currarea.x = 0; currarea.y = 0; currarea.retaddr = 0; push (&s, &currarea); currarea.param = n; currarea.retaddr = 1; start: if (currarea.param ==0){ result = 1; i = currarea.retaddr; popsub(&s, &currarea); switch(i){ case 1: goto label1; case 2: goto label2; } } currarea.x = currarea.param -1; push(&s, &currarea); currarea.param = currarea.x; currarea.retaddr = 2; goto start; label2: currarea.y = result; result = currarea.param*currarea.y; i = currarea.retaddr; popsub(&s, &currarea); switch(i){ case 1: goto label1; case 2: goto label2; } label1: return result; }

Simulação de Recursividade São necessárias todas as variáveis temporais? (n, x, y) n necessita ser empilhada (y=n*fact(x);) Embora x seja definida na chamada nunca será usada depois de retornar (se x e y não fossem declaradas na função e sim globais, a rotina funcionaria igualmente bem. x e y não precisam ser empilhadas E o endereço de retorno?? Só existe um endereço de retorno importante (fact), mas se não empilhamos a area de dados artificial UNDERFLOW Podemos fazer popandtest...

#include<stdio.h> #include<stdlib.h> #define MAXSTACK 50 struct stack { int top; int param[maxstack]; }; int empty(struct stack *s){ return (s->top == -1); } void popandtest(struct stack *s, int *a, short int *und){ if (!empty(s)){ und = 0; *a = s->param[s->top]; s->top--; return; } *und = 1; } void push(struct stack *s, int *a){ s->top++; s->param[s->top] = *a; }

int simfact1(int n){ struct stack s; short int und; long int result, y; int currparam, x; s.top = -1; currparam = n; start: if (currparam == 0){ result = 1; popandtest(&s, &currparam, &und); switch(und){ case 0: goto label2; case 1: goto label1; } } x = currparam -1; push(&s, &currparam); currparam = x; goto start; label2: y = result; result = currparam*y; popandtest(&s, &currparam, &und); switch(und){ case 1: goto label1; case 0: goto label2; } label1: return(result); }

Simulação de Recursividade As instruções goto start e goto label2;?????? Repetições de código Para currparam == 0 e currparam!= 0 popandtest(&s, &currparam, &und); switch(und){ } case 0: goto label2; case 1: goto label1;

int simfact2(int n){ struct stack s; short int und; long int y; int x; s.top = -1; x = n; start: if (x == 0) y = 1; else{ push(&s, x--); goto start; } label1: popandtest(&s, &x, &und); if(und == 1) return(y); label2: y*=x; goto label1; } Repetição normal Repetição normal

int simfact3(int n){ struct stack s; short int und; long int y; int x; s.top = -1; x = n; start: while (x!=0) push(&s, x--); y = 1; popandtest(&s, &x, &und); label1: while (und == 0){ y*=x; popandtest(&s, &x, &und); } return (y); }

int simfact4(int n){ long int y; int x; for(y=x=1; x<=n; x++) y*=x; return (y); }