• Nenhum resultado encontrado

Recursividade

No documento Introdução ao C em 10 aulas (páginas 132-135)

A aula7apresentou os conceitos necessários para construir uma função. Uma função sempre deverá ser invocada por um método externo a ela, assim, uma função em que todas as suas chamadas são externas, são não recursivas ou iterativas. Um procedi- mento recursivo é aquele que possui em seu corpo uma ou mais chamadas a si mesmo (SZWARCFITER; MARKENZON,2015). Ou seja, uma função recursiva possui chamadas internas além da externa.

A recursividade em um procedimento é inerente à sua natureza (EDELWEISS; LIVI,

2014, p. 418), contudo, um procedimento recursivo, em geral, pode ser implementado de forma não recursiva, ou seja, iterativa. Porque implementar um procedimento de maneira recursiva? Essa pergunta não tem um resposta fácil, a recursividade pode apresentar vantagens, como procedimentos com código-fonte mais conciso, claro e limpo, entretanto, boa parte das vezes um procedimento iterativo equivalente pode ser mais eficiente (FEOFILOFF,2008;SZWARCFITER; MARKENZON,2015).

O exemplo mais simples para uma função recursiva é o cálculo do fatorial de um número n > 0. Esse cálculo é recursivo por sua natureza que envolve a multiplicação de todos os números de 1 até n. Assim, o fatorial de n é definido como o produto de todos os inteiros entre n e 1. Exemplo, o fatorial de 4 é: 4 × 3 × 2 × 1 = 24, o fatorial de 3 é: 3 × 2 × 1 = 6 (TENENBAUM; LANGSAM; AUGENSTEIN,1995, p. 133). Portanto, pode-se escrever a definição desta função assim:

n! = 1sen = 0

n! = n × (n − 1) × (n − 2) × ... × 1sen > 0

A seguir, foi disponibilizado o código para uma primeira análise em sua versão iterativa, para então avaliar a versão recursiva. Veja a seguir o código-fonte da função iterativa.

1 #include <stdio.h>

2 #include <stdlib.h>

3

4 int fatorial(int n) {

5 int i, fat = 1;

6 for (i=n; i>=1; i--) {

7 fat *= i; 8 } 9 return fat; 10 } 11 12 void main() 13 {

14 int num, resul;

15 printf("Informe um numero: \n");

16 scanf("%d", &num);

17

18 resul = fatorial(num);

19

20 printf("Fatorial de %d e %d \n", num, resul);

21 }

A função responsável pelo cálculo do fatorial está entre as linhas 4 e 10 do código- fonte. Note que para fazer o cálculo do fatorial, foi necessário um laço for que percorre

8.1. Recursividade 129

todos os números de n até 1. O cálculo é então realizado na linha 7, durante as n iterações. Entre as linhas 12 e 16, temos as instruções responsáveis pela leitura de um número n qualquer e a invocação da função na linha 18, esta é a chamada externa que qualquer função possui, recursiva ou não. Veja que o resultado retornado pela função na linha 18 é atribuído à variável resul e na linha 20 o resultado é impresso. Agora analise a seguir a versão recursiva para o mesmo programa.

1 #include <stdio.h>

2 #include <stdlib.h>

3

4 int fatorial(int n) {

5 if (n <= 1) 6 return 1; 7 else 8 return n * fatorial(n-1); 9 } 10 11 void main() 12 {

13 int num, resul;

14 printf("Informe um numero: \n");

15 scanf("%d", &num);

16

17 resul = fatorial(num);

18

19 printf("Fatorial de %d e %d \n", num, resul);

20 }

A função recursiva para o cálculo do fatorial está compreendida entre as linhas 4 e 9. Notou que não há mais laço for? Isso ocorre porque no caso da função recursiva, não há iterações e sim recursões, que são responsáveis pelas chamadas internas da função, isso obriga a toda função recursiva possuir uma condição de saída da função, pois caso contrário as chamadas internas seriam infinitas. Essa condição pode ser vista na linha 5 do código apresentado, note que, caso o resultado da condição n <= 1 seja verdadeiro, a linha 6 será executada, veja que nesta linha não há uma chamada interna para a função, ou seja, essa é a instrução de saída da função. Da mesma forma, se o resultado da expressão n <= 1 resultar em falso, então a linha 8 será executada, neste caso, a função é invocada novamente.

Agora, observe a linha 8 do código, notou alguma semelhança? Veja que o código é igual à definição feita para a função, isso ocorre porque, em geral, a implementação de uma função recursiva tende a ser mais intuitiva em relação ao problema. Neste caso, um fator importante nesta invocação interna, é que o n é decrementado, n-1, caso não fosse, além do calculo errado, teríamos outra situação de loop infinito, pois a condição n <= 1 nunca seria verdadeira (TENENBAUM; LANGSAM; AUGENSTEIN,1995, p. 135). O restante do programa é igual ao do exemplo anterior.

A figura23mostra um teste de mesa com a função fatorial recursiva, no lado es- querdo da figura23é apresentado o código-fonte à cada chamada e do lado direito os dados do teste de mesa relativo à cada linha do código-fonte, além disso, o teste é realizado com n = 3 na invocação externa à função.

Faça uma análise cuidadosa do teste de mesa apresentado na figura23para entender o funcionamento de uma função recursiva. Veja que na primeira execução da função, n = 3, a condição na linha 5 retorna falso e portanto, a linha 6 não é executada, levando à execução das linhas 7 e 8. Observe que na linha 8, a passagem do argumento n para a

130 Aula 8. Recursividade

função fatorial é n − 1, como n = 3, então n = 3 − 1, portanto, n = 2. Ou seja, na primeira invocação interna da função, o valor de n foi decrementado em 1 unidade. Note que a invocação interna da função, implica em que, a função que acaba de ser invocada, deve primeiro executar para que, somente depois disso, a primeira invocação (externa) da função seja concluída (TENENBAUM; LANGSAM; AUGENSTEIN,1995, p. 134), assim, somente depois da função executar por completo, é que ela será capaz de devolver um valor para a função que a invocou e desta forma, a função que a invocou poderá então, multiplicar esse retorno por n, conforme o código-fonte da linha 8.

Agora veja a invocação interna em que n = 2, novamente o retorno da linha 5 é

falso e a linha 6 não é executada, sendo então executadas as linhas 7 e 8. Na linha 8,

ocorre um novo decremento do valor de n, como no escopo desta invocação da função, n = 2, então, a invocação interna à função fatorial recebe n = 1. Assim, no terceiro escopo da função fatorial, em que n = 1, tem-se que o retorno do código-fonte na linha 5 é verdadeiro e portanto a linha 6 é executada, como no código da linha 6 não há invocação interna da função fatorial, então as iterações irão finalizar neste momento. Agora observe que, neste momento é que a última invocação da função retorna para a sua antecessora o valor 1, que por sua vez, o multiplica por 2 e retorna à primeira invocação (a externa) o valor 2, que o multiplica por 3, retornando então o valor 6 para o método que fez a invocação externa à função.

Figura 23 – Teste de mesa com a função fatorial recursiva

8.2

Loop infinito na recursividade

É de suma importância que um algoritmo recursivo não gere uma sequência infinita de chamadas a si mesmo (TENENBAUM; LANGSAM; AUGENSTEIN,1995, p. 143), pois caso

No documento Introdução ao C em 10 aulas (páginas 132-135)