04 Recursão SCC201/501 - Introdução à Ciência de Computação II

Documentos relacionados
01 Análise de Algoritmos (parte 1) SCC201/501 - Introdução à Ciência de Computação II

Algoritmos e Estruturas de Dados I Linguagem C

Técnicas de projeto de algoritmos: Indução

SCC Capítulo 2 Recursão

05 Análise de Algoritmos (parte 4) SCC201/501 - Introdução à Ciência de Computação II

Estrutura de Dados Conceitos Iniciais

Recursividade. Métodos iterativos. Prof. Cesar Augusto Tacla. Métodos iterativos utilizam estruturas de repetição

Algoritmos e Estruturas de Dados

01 Análise de Algoritmos (parte 2) SCC201/501 - Introdução à Ciência de Computação II

Revisão: Tipo Abstrato de Dados Recursividade

Recursividade. Prof. Jesus José de Oliveira Neto

Prof. A. G. Silva. 25 de setembro de Prof. A. G. Silva INE5603 Introdução à POO 25 de setembro de / 35

Algoritmos e Estruturas de Dados

Programação Estruturada

ALGORITMOS AVANÇADOS UNIDADE II Recursividade. Luiz Leão

Recursão. Prof. Fabrício Olivetti de França. (com inspirações do slide do prof. Rodrigo Hausen)

Recursividade. Estrutura de Dados. Prof. Kleber Rezende

Aula 05: - Recursão (parte 1)

Aula 05: - Recursão (parte 1)

Introdução à Ciência da Computação II. Recursão. Prof. Ricardo J. G. B. Campello

Aula prática 5. Funções Recursivas

Programação. Prof Marcelo Zorzan Prof a Melissa Zanatta

MC102 Aula 26. Instituto de Computação Unicamp. 17 de Novembro de 2016

Universidade Federal de Uberlândia Faculdade de Computação. Linguagem C: funções

Recursão David Déharbe

Estruturas de Dados, Análise de Algoritmos e Complexidade Estrutural. Carlos Alberto Alonso Sanches

Técnicas de análise de algoritmos

14 Projeto de Algoritmos: paradigmas SCC201/501 - Introdução à Ciência de Computação II

Introdução a Algoritmos Parte 08

Processamento da Informação

07 Ordenação em Memória Interna (parte 2) quicksort SCC201/501 - Introdução à Ciência de Computação II

03 Análise de Algoritmos (parte 3) SCC201/501 - Introdução à Ciência de Computação II

Algoritmos e Programação. AULA 21: Recursividade UNIVERSIDADE FEDERAL DE PELOTAS CENTRO DE DESENVOLVIMENTO TECNOLÓGICO CIÊNCIA DA COMPUTAÇÃO

Permite modularidade (dividir programa em partes): Facilita a depuração (debug) e portabilidade.

Roteiro Prático Nº 13 Recursividade

14 Projeto de Algoritmos: paradigmas SCC201/501 - Introdução à Ciência de Computação II

Recursividade. Objetivos do módulo. O que é recursividade

SCC0214 Projeto de Algoritmos

Programação II RECURSÃO

SCC Capítulo 3 Análise de Algoritmos - Parte 2

Algoritmos e Estruturas de Dados I

Recursividade. David Menotti Algoritmos e Estruturas de Dados II DInf UFPR

Bruno Hott Algoritmos e Estruturas de Dados I DECSI UFOP. Recursividade

Fundamentos de programação

Algoritmos e Estruturas de Dados I 01/2013. Vetores e Recursividade. Pedro O.S. Vaz de Melo

03 Grafos: percurso, ponderação e caminhos SCC0503 Algoritmos e Estruturas de Dados II

1. Faça um programa que leia uma string digitada pelo usuário e salve em um arquivo em branco.

Algoritmos, Estruturas de Dados e Tipos Abstratos de Dados (TADs)

LINGUAGEM C: FUNÇÕES FUNÇÃO 04/07/2017. Funções são blocos de código que podem ser nomeados e chamados de dentro de um programa.

Estruturas de Dados. Revisão de Funções e Recursão. Agradecimentos

PROGRAMAÇÃO DE COMPUTADORES V - TCC Modulo 6 : Funções Escopo de Variáveis: Globais x Locais Aura - Erick

Recursividade Alguns problemas são definidos com base nos mesmos, ou seja, podem ser descritos por instâncias do próprio problema.

Listas Estáticas. Prof. Fernando V. Paulovich *Baseado no material do Prof. Gustavo Batista

Aula 3: Algoritmos: Formalização e Construção

Programação científica C++

SCC0601 Projeto de Algoritmos. Recursão

Recursão. Prof. Cristiano André da Costa. [Versão de Março de 2000] Definição

Introdução à Programação / Programação I

LINGUAGEM C: FUNÇÕES FUNÇÃO 08/01/2018. Funções são blocos de código que podem ser nomeados e chamados de dentro de um programa.

UNIVERSIDADE FEDERAL RURAL DO SEMI-ÁRIDO CURSO: CIÊNCIA DA COMPUTAÇÃO. Prof.ª Danielle Casillo

Recursividade. Recursividade

Recursão. Aula 1. Liana Duenha. Faculdade de Computação Universidade Federal de Mato Grosso do Sul

BC1424 Algoritmos e Estruturas de Dados I Aula 03: Recursão / Recursividade

Universidade Federal do ABC Programação Estruturada Fabrício Olivetti França Lista de Exercícios 02

13 Hashing (parte 2) SCC201/501 - Introdução à Ciência de Computação II

MC102 Algoritmos e Programação de Computadores

Aula 05. Modularização Função Subrotina Recursividade

Análise e Complexidade de Algoritmos

BCC402 Algoritmos e Programação Avançada Prof. Marco Antonio M. Carvalho Prof. Túlio Ângelo M. Toffolo 2011/1

Programação Estruturada Prof. Rodrigo Hausen Recursão

# Estrutura de Dados # Aula 08 Recursão (conceito, utilização, exemplos) Prof. Leinylson Fontinele Pereira

Estruturas de Dados Aula 14: Recursão

Recursividade, Tentativa e Erro

Estruturas de Dados Aula 14: Recursão 19/05/2011

Estruturas de Dados. Módulo 4 Funções. 9/8/2005 (c) Dept. Informática - PUC-Rio 1

Análise de Algoritmos Parte 4

Recursividade UFOP 1/48

01 Grafos: parte 1 SCC0503 Algoritmos e Estruturas de Dados II

05 Grafos: ordenação topológica SCC0503 Algoritmos e Estruturas de Dados II

Processamento da Informação Teoria. Recursividade

Programação: Vetores

Algoritmos e Estrutura de Dados II. Árvore. Prof a Karina Oliveira.

Universidade Federal de Uberlândia Faculdade de Computação. Linguagem C: funções

Estrutura de Dados. Ricardo José Cabeça de Souza Parte 4

Projeto e Análise de Algoritmos Projeto de Algoritmos Programação Dinâmica. Prof. Humberto Brandão

Programação Estruturada

Algoritmos e Estruturas de Dados I. Recursividade. Pedro O.S. Vaz de Melo

Análise de Problemas Recursivos. Algoritmos e Estruturas de Dados Flavio Figueiredo (

Algoritmos e Programação. Linguagem C Procedimentos e. Eliane Pozzebon

INF1007: Programação 2. 0 Revisão. 06/08/2015 (c) Dept. de Informática - PUC-Rio 1

ESTRUTURA DE DADOS (TCC )

Suponha um conjunto habitacional, com várias famílias... imagina se todas elas morassem em uma única casa?

Capítulo 3: Repetições. Pontifícia Universidade Católica Departamento de Informática

Suponha um conjunto habitacional, com várias famílias... imagina se todas elas morassem em uma única casa?

Universidade de São Paulo São Carlos Instituto de Ciências Matemáticas e de Computação. Recursão em C

Introdução à Programação

Construção de Algoritmos II Aula 06

Algoritmos. Laura Goulart. 11 de Dezembro de 2018 UESB. Laura Goulart (UESB) Algoritmos 11 de Dezembro de / 12

Apresentação SCC0204 Programação Orientada a Objetos

Transcrição:

04 Recursão SCC201/501 - Introdução à Ciência de Computação II Prof. Moacir Ponti Jr. www.icmc.usp.br/~moacir Instituto de Ciências Matemáticas e de Computação USP 2010/2 Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 1 / 36

Sumário 1 Recursividade Denições Recursão e computação 2 Exemplos e Implementação Exemplo: cálculo do fatorial Implementação de Recursividade Exemplo: sequência de Fibonacci 3 Questões importantes Quando não usar recursividade Recursão indireta Recursão innita Ordem da chamada recursiva Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 2 / 36

Prévias: notícias e páginas interessantes a visitar Foi provado que qualquer posição do Cubo Mágico pode ser resolvida com 20 movimentos. http://www.reddit.com/tb/cz0ll Martin e o Dragão, série de três contos sobre recursão (Prof. Ruiter UFAM), http://www.dcc.ufam.edu.br/~ruiter/icc/martin0.html http://www.dcc.ufam.edu.br/~ruiter/icc/martin1.html http://www.dcc.ufam.edu.br/~ruiter/icc/martin2.html Uncyclopedia sobre recursão nita. http://uncyclopedia.wikia.com/wiki/finite_recursion Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 3 / 36

Denições Em matemática, pode ser denida como: o ato de denir um objeto (geralmente uma função), em termos do próprio objeto. Em computação, ocorre quando: um dos passos de um determinado algoritmo envolve a repetição desse mesmo algoritmo Um procedimento que se utiliza da recursão é dito recursivo. Também é dito recursivo qualquer objeto que seja resultado de um procedimento recursivo. Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 4 / 36

Denições É possível, por meio de recursão, obter um objeto ou sequências innitas a partir de um componente nito. O conjunto dos números naturais, por exemplo, pode ser denido formalmente (de maneira resumida), por: Seja 0 um número natural. Cada número natural, n tem um sucessor n + 1, que é também um número natural. Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 5 / 36

Denições Caso base Parte não recursiva, também chamada de âncora, ocorre quando a resposta para o problema é trivial. Passo indutivo Parte da denição que especica como cada elemento (solução) é gerado a partir do precedente. A função fatorial n! pode ser denida como, dado um número inteiro positivo n: { 1, se n = 0 (caso base), n! = n (n 1)!, se n > 0 (passo de indução). (1) Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 6 / 36

Aplicação visual Efeito Droste Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 7 / 36

Humor recursivo Denição de: Recursão Se você ainda não entendeu; ver Recursão. Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 8 / 36

Humor recursivo Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 9 / 36

Recursão e computação Gramáticas de linguagens de programação Na especicação de gramáticas de linguagens de programação se utiliza recursão para modelar a estrutura de expressões e declarações. <expr> ::= <numero> (<expr> * <expr>) (<expr> + <expr>) O exemplo acima mostra que a expressão pode ser um número, o produto de duas expressões ou a soma de duas expressões. A referência recursiva à <expr> permite expressões arbitrariamente complexas com mais de um produto ou soma em uma única expressão, como: (5 * ((3 * 6) + 8)) Qual é o caso base? E o que ele representa? Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 10 / 36

Recursão e computação Problemas com estrutura recursiva Propriedade: cada instância do problema contém uma instância menor do mesmo problema. Resolução de problemas recursivos se a instância é pequena, resolva-a diretamente (caso base) senão 1 reduza-a a uma instância menor do mesmo problema, 2 aplique o método à instância menor, e 3 volte à instância original. Algoritmo recursivo O uso da estratégia acima produz um algoritmo recursivo que é caracterizado por possuir uma chamada a si mesmo. Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 11 / 36

Recursão e computação: as três regras 1 Saber quando parar. qualquer função recursiva deve vericar se a jornada já terminou (caso base) antes da nova chamada recursiva. 2 Decidir como fazer o primeiro passo pensar em como quebrar um problemas em subproblemas que possam ser resolvidos instantaneamente. 3 Analisar a jornada de forma que possa ser dividida em jornadas menores encontrar uma maneira da função chamar a si mesma (recursivamente), passando por parâmetro um problema menor resultante da segunda regra. Fonte: http://www.dcc.ufam.edu.br/~ruiter/icc/martin4.html Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 12 / 36

Exemplo: cálculo do fatorial Função recursiva para cálculo do fatorial unsigned long fatorial(int n) { unsigned long resultado = 1; // caso base if (n > 1) { resultado = n * fatorial(n-1); // passo indutivo } return resultado; } Na função acima, é possível ver que o caso base é tomado como sendo o padrão. A seguir, se n > 1, então não estamos no caso base e assim o resultado será o produto de n por (n 1)!. Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 13 / 36

Implementação de Recursividade A forma de um compilador implementar um procedimento recursivo é por meio de uma pilha. Nessa pilha são armazenados os dados usados em cada chamada de uma função que ainda não terminou de processar. fatorial(4) Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 14 / 36

Implementação de Recursividade A forma de um compilador implementar um procedimento recursivo é por meio de uma pilha. Nessa pilha são armazenados os dados usados em cada chamada de uma função que ainda não terminou de processar. fatorial(4) [ 4 * fatorial(3) ] Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 15 / 36

Implementação de Recursividade A forma de um compilador implementar um procedimento recursivo é por meio de uma pilha. Nessa pilha são armazenados os dados usados em cada chamada de uma função que ainda não terminou de processar. fatorial(4) [ 4 * fatorial(3) ] [ 4 * < 3 * fatorial(2) > ] Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 16 / 36

Implementação de Recursividade A forma de um compilador implementar um procedimento recursivo é por meio de uma pilha. Nessa pilha são armazenados os dados usados em cada chamada de uma função que ainda não terminou de processar. fatorial(4) [ 4 * fatorial(3) ] [ 4 * < 3 * fatorial(2) > ] [ 4 * < 3 * { 2 * fatorial (1) } > ] Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 17 / 36

Implementação de Recursividade A forma de um compilador implementar um procedimento recursivo é por meio de uma pilha. Nessa pilha são armazenados os dados usados em cada chamada de uma função que ainda não terminou de processar. fatorial(4) [ 4 * fatorial(3) ] [ 4 * < 3 * fatorial(2) > ] [ 4 * < 3 * { 2 * fatorial (1) } > ] [ 4 * < 3 * { 2 * 1 } > ] Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 18 / 36

Implementação de Recursividade A forma de um compilador implementar um procedimento recursivo é por meio de uma pilha. Nessa pilha são armazenados os dados usados em cada chamada de uma função que ainda não terminou de processar. fatorial(4) [ 4 * fatorial(3) ] [ 4 * < 3 * fatorial(2) > ] [ 4 * < 3 * { 2 * fatorial (1) } > ] [ 4 * < 3 * { 2 * 1 } > ] [ 4 * < 3 * 2 > ] Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 19 / 36

Implementação de Recursividade A forma de um compilador implementar um procedimento recursivo é por meio de uma pilha. Nessa pilha são armazenados os dados usados em cada chamada de uma função que ainda não terminou de processar. fatorial(4) [ 4 * fatorial(3) ] [ 4 * < 3 * fatorial(2) > ] [ 4 * < 3 * { 2 * fatorial (1) } > ] [ 4 * < 3 * { 2 * 1 } > ] [ 4 * < 3 * 2 > ] [ 4 * 6 ] Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 20 / 36

Implementação de Recursividade A forma de um compilador implementar um procedimento recursivo é por meio de uma pilha. Nessa pilha são armazenados os dados usados em cada chamada de uma função que ainda não terminou de processar. fatorial(4) [ 4 * fatorial(3) ] [ 4 * < 3 * fatorial(2) > ] [ 4 * < 3 * { 2 * fatorial (1) } > ] [ 4 * < 3 * { 2 * 1 } > ] [ 4 * < 3 * 2 > ] [ 4 * 6 ] [ 24 ] Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 21 / 36

Implementação de Recursividade A função começa a execução do seu primeiro comando cada vez que é chamada Novas e distintas cópias dos parâmetros passados por valor e variáveis locais são criadas A posição que chama a função é colocada em estado de espera o nível gerado recursivamente é executado fatorial(4) [ 4 * fatorial(3) ] [ 4 * < 3 * fatorial(2) > ] [ 4 * < 3 * { 2 * fatorial (1) } > ] [ 4 * < 3 * { 2 * 1 } > ] [ 4 * < 3 * 2 > ] [ 4 * 6 ] [ 24 ] Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 22 / 36

Implementação de Recursividade Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 23 / 36

Sequência de Fibonacci Sequência numérica obtida de forma recursiva: 0, se n = 0, f (n) = 1, se n = 1, f (n 1) + f (n 2), se n > 1. (2) Inicialmente relacionado à velocidade de reprodução de coelhos e observado como sendo o modelo de muitos fenômenos biológicos, possui inúmeras aplicações na computação, matemática, teoria dos jogos, artes e música. Os primeiros dez termos da sequência são: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55 Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 24 / 36

Sequência de Fibonacci Um uso interessante é na conversão de milhas para quilômetros. Para saber converter 5 mil. em km. aproximadamente, olha-se para o número seguinte ao número de Fibonacci correspondendo ao número de milhas: 5 mil. são aproximadamente 8 km. Figura: A evolução da espiral da folha da bromélia Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 25 / 36

Sequência de Fibonacci Uma função que calcule o número de Fibonacci para qualquer valor de n pode ser construída diretamente usando uma estratégia recursiva: 0, se n = 0, f (n) = 1, se n = 1, (3) f (n 1) + f (n 2), se n > 1. unsigned int Fib(unsigned int n) { if (n<=1) return n; // caso base else return (Fib(n-1) + Fib(n-2)); } // passo indutivo Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 26 / 36

Sequência de Fibonacci Para valores de entrada pequenos, o programa é rápido. Já para n > 40 o computador demora um certo tempo para processar. Vamos inserir mensagens de monitoramento na função para vericar. unsigned int Fib(unsigned int n) { printf("> Entrando em Fib(%d)\n",n); unsigned int F; if (n<=1) F = n; else F = (Fib(n-1) + Fib(n-2)); } printf("<< Saindo de Fib(%d), retorno=%d\n", n, F); return F; Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 27 / 36

Sequência de Fibonacci A saída do monitoramento, para n = 4 é: > Entrando em Fib(4) > Entrando em Fib(3) > Entrando em Fib(2) > Entrando em Fib(1) << Saindo de Fib(1), retorno=1 > Entrando em Fib(0) << Saindo de Fib(0), retorno=0 << Saindo de Fib(2), retorno=1 > Entrando em Fib(1) << Saindo de Fib(1), retorno=1 << Saindo de Fib(3), retorno=2 > Entrando em Fib(2) > Entrando em Fib(1) << Saindo de Fib(1), retorno=1 > Entrando em Fib(0) << Saindo de Fib(0), retorno=0 << Saindo de Fib(2), retorno=1 << Saindo de Fib(4), retorno=3 Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 28 / 36

Sequência de Fibonacci Figura: A árvore de chamadas recursivas à função Fib() Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 29 / 36

Sequência de Fibonacci: algoritmo iterativo unsigned int Fib_iter(unsigned int n) { unsigned int k, i = 1, F = 0; } for (k = 1; k <= n; k++) { F += i; i = F - i; } return F; Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 30 / 36

Quando não usar recursividade No exemplo anterior, a primeira implementação seguia a estrutura natural da sequência de Fibonacci. Mas, como vimos, nem sempre a estratégia recursiva é a melhor. Os problemas para os quais algoritmos recursivos devem ser evitados são ditos terem recursividade de cauda, e devem substituídos por uma versão iterativa. nesse tipo de função, a chamada recursiva é a última instrução a ser executada. Há, no entanto, problemas para os quais é difícil ou impossível implementar uma solução não recursiva. Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 31 / 36

Recursão indireta Funções podem ser recursivas indiretamente, fazendo isto através de outras funções: assim, P pode chamar Q que chama R e assim por diante, até que P seja novamente invocada. Um exemplo é a análise de expressões (como no exemplo anterior): um analisador gramatical para cada tipo de sub-expressão, uma expressão "3 + (2 * (4 + 4))"é a resolvida da seguinte forma: 1 A função que processa expressões "+"chama uma segunda função que processa expressões "*", 2 A função de multiplicação, por sua vez, chama novamente a função de soma. Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 32 / 36

Recursão innita Repetição innita causada por chamada recursiva. Ocorre quando o caso base não é denido (ou não é denido corretamente). Na prática, o programa não irá executar innitamente, pois em algum momento alcançará o limite da pilha, e haverá um estouro de memória, causando um erro. Exemplo: long int fatorial(int n) { return n * fatorial(n-1); } Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 33 / 36

Ordem da chamada recursiva void recursiva1(int num){ if (num <= 4) { printf("%d\n", num); recursiva1(num+1); } } void recursiva2(int num){ if (num <= 4) { recursiva1(num+1); printf("%d\n", num); } } recursiva1(1) printf(1) recursiva1(1+1) printf(2) recursiva1(2+1) printf(3) recursiva1(3+1) printf(4) recursiva2(1) recursiva2(1+1) recursiva2(2+1) recursiva2(3+1) printf(4) printf(3) printf(2) printf(1) Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 34 / 36

Exercícios (1) Implemente as versões recursiva e iterativa da função para obter números de Fibonacci. Utilize a biblioteca time.h para medir e observar o tempo necessário para calcular n = 15, 30, 45 e 60, utilizando as duas versões. (2) Implemente uma função recursiva para encontrar o maior elemento em um arranjo. Dica: encontre o maior elemento no subconjunto que contém todos, exceto o último elemento, então compare aquele máximo com o valor do último elemento. (3) Implemente uma função que exibe todas as substrings de uma string. Dica: primeiro enumere todos os substrings que começam com o primeiro caractere. Existem n deles se o string tem tamanho n. Então, enumere as substrings da string após remover o primeiro caractere. Exemplo: substrings de rum: r, ru, rum, u, um, m Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 35 / 36

Bibliograa ZIVIANI, N. Projeto de algoritmos: com implementações em Pascal e C (Seção 2.2). 2.ed. Thomson, 2004. CORMEN, T.H. et al. Algoritmos: Teoria e Prática (Seção 2.3.1). Campus. 2002. FEOFILOFF, P. Recursão e algoritmos recursivos. Disponível em: http://www.ime.usp.br/~pf/algoritmos/aulas/recu.html. CALDAS, R.B.. Introdução a Computação. Disponível em: http://www.dcc.ufam.edu.br/~ruiter/icc/. Moacir Ponti Jr. (ICMCUSP) 04Recursão 2010/2 36 / 36