Aula 16: Programação Recursiva |
|
result = 1;
/* initialize the variable */
for (i=1; i<=n; i++)
result = i*result;
return(result);
}
Esta função de facto irá retornar o factorial
do argumento, por exemplo factorial(5)
= 120.
Uma solução muito mais interessante é através da definição da função factorial em termos de si mesma, tal como aprendemos na escola,
n! = n*(n-1)!
Vamos fazer exactamente isso:
int factorial(int n)
/* should return n! */
{
/* the value to be returned
is expressed in terms of itself: */
factorial = n*factorial(n-1);
}
Esta função está quase correcta. O único problema é que nunca irá parar de se chamar a si própria. Por exemplo, podemos chamá-la com factorial(4), que irá depois tentar calcular 4*factorial(3) e assim chamar factorial(3). factorial(3) irá tentar calcular 3*factorial(2), que irá chamar factorial(2), ... que irá chamar factorial(1) ... que irá chamar factorial(0) ... que irá chamar factorial(-1) ... que irá chamar factorial(-2) ... e por aí fora. O programa nunca irá retornar nada e o computador irá encravar, gerando provavelmente um erro do tipo "stack overflow". Claramente, temos que construir a função de forma a que em determinada altura ela páre de se chamar a si própria. Relembrar que na forma matemática de definir uma função em termos de si mesma temos sempre que incluir uma forma de paragem, para a função factorial é |
1! = 1
Vamos colocar a forma de paragem na nossa função:
int factorial(int n)
/* returns n! */
{
if (n==1)
return(1);
else
return(n*Factorial(n-1));
}
A ideia que importa reter é que se deve incluir na função
a possibilidade de ela obter um resultado e terminar o cálculo recursivo.
Tal como temos que dar a um ciclo a possibilidade de terminar, temos que
dar essa possibilidade também às funções recursivas.
Caso contrário, o programa continuará para sempre (ou irá
encravar).
Podemos implementar isto numa função, reparar na condição
de paragem:
int fibonacci(int n)
{
if ((n==1) || (n==2))
return(1);
else
return(fibonacci(n-2)
+ fibonacci(n-1));
}
m = 2*n;
printf("%d ", m);
if (n==1) then
result = 1;
else
result = n*factorial(n-1);
printf("%d ", m);
return(result);
}
Quando chamamos a função com argumento 3, irá
acontecer o seguinte:
|
|
factorial(3) é chamada | |
são criadas as variáveis n, m e result | m=* r=* n=* |
3 é atribuído a n (da chamada da função)
2*3 é atribuído a m |
m=6 r=* n=3 |
factorial(2) é chamada | m=6 r=* n=3 |
são criadas as variáveis n, m
e result
(novas; diferentes das anteriores!) |
m=* r=* n=* m=6 r=* n=3 |
2 é atribuído a n (da chamada
da função)
2*2 é atribuído a m |
m=4 r=* n=2 m=6 r=* n=3 |
factorial(1) é chamada | m=4 r=* n=2 m=6 r=* n=3 |
são criadas as variáveis
n, m e result
(diferentes das de cima) |
m=* r=* n=* m=4 r=* n=2 m=6 r=* n=3 |
1 é atribuído a n
(da chamada da função)
2*1 é atribuído a m |
m=2 r=* n=1 m=4 r=* n=2 m=6 r=* n=3 |
... chegámos à condição de paragem e result = 1; | m=2 r=1 n=1 m=4 r=* n=2 m=6 r=* n=3 |
é escrito o valor de m: 2 | m=2 r=1 n=1 m=4 r=* n=2 m=6 r=* n=3 |
o valor de result (1) é retornado
para a instrução de chamada
factorial(1) termina, os últimos n, m e result são destruídos |
m=4 r=* n=2 m=6 r=* n=3 |
result é calculado: n*factorial(n-1)
fica
n*'valor retornado' -> 2*1 = 2 |
m=4 r=2 n=2 m=6 r=* n=3 |
é escrito o valor de m: 4 | m=4 r=2 n=2 m=6 r=* n=3 |
o valor de result (2) é retornado para
a instrução de chamada
factorial(2) termina, os últimos n, m e result são destruídos |
m=6 r=* n=3 |
result é calculado: n*factorial(n-1) fica
n*'valor retornado' -> 3*2 = 6 |
m=6 r=6 n=3 |
é escrito o valor de m: 6 | m=6 r=6 n=3 |
o valor de result (6) é retornado para a instrução
de chamada
factorial(3) termina, os últimos n, m e result são destruídos |
|
o valor retornado por factorial(3) é 6 |