Tutoria AEDSI
Pablo Silva
Recursividade
Muitos algoritmos têm a seguinte propriedade:
cada instância do problema contém uma instância
menor do mesmo problema. Dizemos que esses
problemas têm estrutura recursiva, porque é
possível resolver o problema chamando à si mesmo
com uma instância menor do problema.
Recursividade
Uma função que chama à si mesmo é dita recursiva.
Funções que chamam outras funções
Esse conceito tem que ficar bem claro: Uma função
pode chamar uma outra ou mais funções. Vamos ver
um exemplo.
Calcular a mesada
Suponha que queremos um programa para calcular a mesada de nossos filhos, baseado
em suas idades e notas. Seja então a seguinte função calcMesada. Não se preocupem
com a main, ela logo aparecerá. Não precisamos criar a main primeiro sempre, mas ela
terá que ser criada em algum momento!
O que esta função faz é receber um
parâmetro que será a idade do nosso
filho e retorna um valor maior da
mesada para filhos maiores de idade.
Calcular a mesada
Digamos agora que, a mesada de nossos filhos menores de idade, tem que ser recompensada (ou não!)
por suas notas. Então criamos a seguinte função que dá um bônus ou um desconto (bd) para nosso filho
menor de idade.
Essa função recebe três
parâmetros: a idade, a nota e o
valor da mesada já calculada
pela função anterior. Por isso é
muito importante chamar as
funções na ordem em que
queremos os resultados. Se não
calcularmos a mesada antes com
a outra função, como vamos
passa-la como parâmetro aqui!?Se a idade do nosso filho for menor que 18, vamos variar a mesada de
acordo com a nota dele, senão, vamos somente retornar o mesmo valor
da mesada que passamos para a função.
Calcular a mesada
Na main, vamos receber o
valor da idade e a nota
através da função scanf
(permite que o usuário
digite valores e armazena
nas variáveis passada como
parâmetro).
Após isso, chamamos a
função calcMesada para
calcular a mesada e
atribuímos este valor a
variável mesada.
Agora vamos chamar a
nossa segunda função e
passando como parâmetro
a própria mesada obtida
anteriormente.
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
8
?
?
?
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
8
?
?
?
Passo 1: variável mesada é criada
sem valor algum por enquanto.
mesada
&43jjuiop
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
8
?
?
?
Passo 2: variável idade é criada sem
valor algum por enquanto.
mesada
&43jjuiop
idade
&4399uiop
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
8
?
?
?
Passo 3: variável nota é criada sem
valor algum por enquanto.
mesada
&43jjuiop
idade
&4399uiop
nota
&43666iop
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
8
?
?
?
Passo 4: mensagem exibida na tela:
Entre com a idade do seu filho:
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
8
?
?
?
Passo 5: o usuário digita um valor para idade
e esse valor vai para a variável idade.
Entre com a idade do seu filho: 10
10
idade
&4399uiop
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
8
?
?
?
Passo 6: mensagem é exibida na tela
Entre com a idade do seu filho: 10
Entre com a nota geral do seu filho:
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
8
?
?
?
Passo 7: o usuário entra com o valor da nota
e esse valor vai direto para a variável nota.
Entre com a idade do seu filho: 10
Entre com a nota geral do seu filho: 1
1
nota
&43666iop
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
8
?
?
?
Vamos para a função!
A seta está para cima porque
uma função que é chamada por
outra função sempre deve ser
declarada acima da função que à
está chamando. Do contrário, a
função não conseguirá chama-
la!
10
Estamos passando o valor
da idade e não uma
referência. Por isso nossa
caixinha só tem um valor
e nada de referências para
a variável idade.
(Recebemos este valor
anteriormente!)
Vamos executar este programa
int calcMesada(int idade){
if(idade < 18)
return idade*20;
else {
return idade*50;
}
}
Passo 9: Uma nova caixinha (varíavel)
chamada idade é criada e o valor que
“jogamos” (passamos como parâmetro na
chamada da função) para a função é
colocado lá dentro.
10
9
10
11
12
13
14
10
idade
&9999uiop
Muito importante entender aqui
que essa caixinha tem o mesmo
nome que a caixinha da idade que
está na main. Mas como pode ser
visto os endereços são diferentes.
ELAS NÃO SÃO A MESMA VARIÁVEL,
SOMENTE TEM O MESMO NOME.
Já sabemos que não podemos ter
duas variáveis com o mesmo nome,
mas esta regra é válida para
mesmas funções. Funções
diferentes podem ter variáveis com
mesmo nome, que é o nosso caso!
Lembre-se, uma função não consegue ver
nada que está dentro de outra função. O
escopo de uma função é digamos
“secreto” para todas as outras!
Vamos executar este programa
int calcMesada(int idade){
if(idade < 18)
return idade*20;
else {
return idade*50;
}
}
Passo 10: Verificamos se a idade é menor
que 18. Para este nosso caso ela é, então o
passo 11 será executado!
9
10
11
12
13
14
10
idade
&9999uiop
Lembre-se, uma função não consegue ver
nada que está dentro de outra função. O
escopo de uma função é digamos
“secreto” para todas as outras!
Vamos executar este programa
int calcMesada(int idade){
if(idade < 18)
return idade*20;
else {
return idade*50;
}
}
Passo 11: Encontramos a palavra return.
Portanto neste momento vamos retornar o
valor da multiplicação de idade por 20 para o
local onde esta função foi chamada. Neste
caso é a na main.9
10
11
12
13
10
idade
&9999uiop
Importante: os passos 12, 13 nunca serão
executados, pois uma vez que em uma
função, é encontrado a palavra de retorno, ela
imediatamente interrompe sua execução e
retorna o valor passado para o return.
200
Só podemos retornar valores que já temos. Por
isso, o retorno para a main só vai acontecer
quando o computador processar a operação
idade*20 e substituir o valor desta multiplicação
na expressão. Se o computador demorasse 10
anos para computar esta multiplicação, então
demoraríamos 10 anos para voltar para a main!
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
812
?
?
Passo 12: a caixinha de
mesada recebe o valor de
retorno da função.
13
200
mesada
&43jjuiop
200
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
812
?
?
Passo 13: vamos novamente para outra
função. Chamamos bdMesada enviando os
valores dos nossos três parâmetros!
(Passagem por valor!)
13
200
mesada
&43jjuiop
10
idade
&4399uiop
1
nota
&43666iop
10
1
200
Vamos executar este programa
int bdMesada(int idade, int notas, int mesada){
if(idade < 18)
return mesada*notas;
return mesada;
}
Passo 14: São criadas novas caixinhas para os
nossos parâmetros que vão receber os
valores enviados na chamada da função, na
mesma ordem enviada.
14
15
16
17
Lembre-se, uma função não consegue ver
nada que está dentro de outra função. O
escopo de uma função é digamos
“secreto” para todas as outras!
200
mesada
&99yjuiop
10
idade
&4oouiop
1
nota
&4wertiop
MESMOS NOMES, MAS
ENDEREÇOS DIFERENTES!
10 1 200
Vamos executar este programa
int bdMesada(int idade, int notas, int mesada){
if(idade < 18)
return mesada*notas;
return mesada;
}
Passo 15: Vamos ver se a idade é menor que
18. Para o nosso caso é, então vamos
executar o passo 16.
14
15
16
17
Lembre-se, uma função não consegue ver
nada que está dentro de outra função. O
escopo de uma função é digamos
“secreto” para todas as outras!
200
mesada
&99yjuiop
10
idade
&4oouiop
1
nota
&4wertiop
MESMOS NOMES, MAS
ENDEREÇOS DIFERENTES!
Vamos executar este programa
int bdMesada(int idade, int notas, int mesada){
if(idade < 18)
return mesada*notas;
return mesada;
}
Passo 16: Encontramos a palavra return e
então vamos retornar para o local que esta
função foi chamada, retornando o valor de
mesada*notas que para nosso caso é 200*1
= 200. O passo 17 então não será executado,
pois interrompemos a execução no
momento do retorno.
14
15
16
17
Lembre-se, uma função não consegue ver
nada que está dentro de outra função. O
escopo de uma função é digamos
“secreto” para todas as outras!
200
mesada
&99yjuiop
10
idade
&4oouiop
1
nota
&4wertiop
200
Novamente, retornamos
valores e nunca expressões!
Para que a função retorne para
onde foi chamada, o
computador primeiro tem que
fazer a multiplicação e devolver
um valor para o retorno!
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
812
15
16
Passo 14: a caixinha da mesada, vai receber
o valor de retorno da função. Como já
tínhamos um valor lá, ele será substituído
pelo novo. Coincidentemente, este valor é o
mesmo, porque nossa multiplicação na
função foi por 1. De qualquer maneira o
valor será substituído, mesmo que seja pelo
mesmo valor!
13
10
idade
&4399ui
1
nota
&43666iop
14
200
200
mesada
&43jjuiop
200
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
812
15
16
Passo 15: É exibida uma mensagem na tela com o valor
da variável mesada, que é a saída final do nosso
programa e o objetivo que queríamos atingir.
1314
200
Entre com a idade do seu filho: 10
Entre com a nota geral do seu filho: 1
O valor da mesada para seu filho e: 200.
Vamos executar este programa
int main(){
int mesada;
int idade;
int nota;
printf("Entre com a idade do seu filho:");
scanf("%d", &idade);
printf("Entre com a nota geral do seu filho:");
scanf("%d", &nota);
mesada = calcMesada(idade);
mesada = bdMesada(idade,nota,mesada);
printf("nnO valor da mesada para seu filho e: %d", mesada);
return 0;
}
1
2
3
4
5
6
7
812
15
16
Passo 16: Programa termina. É exibida na tela uma
mensagem padrão da linguagem.
1314
200 Entre com a idade do seu filho: 10
Entre com a nota geral do seu filho: 1
O valor da mesada para seu filho e: 200.
Program returned with execution of
0.2222s
Recursividade
Como já vimos que uma função pode chamar uma
ou mais funções, então não há porque duvidar que
uma função pode chamar à ela mesma! Vamos ver
como funciona então uma função recursiva.
Vamos ver um exemplo
int main(){
exemplo(‘c’);
return 0;
}
void exemplo(char a){
printf(“%c”, a);
exemplo(a);
}
Digamos que temos a função exemplo e chamamos ela na main passando o caracter ‘c’. Vamos ver como
será a execução.
1
2
3
4
5 ?
Vamos ver um exemplo
int main(){
exemplo(‘c’);
return 0;
}
1
2
?
Passo 1: o programa se inicia.
Vamos ver um exemplo
int main(){
exemplo(‘c’);
return 0;
}
1
2
?
Passo 2: vamos para a função e estamos
passando o caracter ‘c’ utilizando passagem
por valor. Dessa vez nem mesmo temos
variáveis na main. Só estamos querendo
chamar a função para ver o qual é seu
comportamento recursivo.
c
Vamos ver um exemplo
void exemplo(char a){
printf(“%c”, a);
exemplo(a);
}
3
4
5
Passo 3: Uma variável (caixinha) do tipo
char é criada e o valor passado na
chamada da função é atribuído à ela.
c
c
a
&3399uiop
Vamos ver um exemplo
void exemplo(char a){
printf(“%c”, a);
exemplo(a);
}
3
4
5
Passo 4: Imprimimos o caracter que está
na variável a na tela.
c
a
&3399uiop
c
Vamos ver um exemplo
void exemplo(char a){
printf(“%c”, a);
exemplo(a);
}
3
4
5
Passo 5: O passo cinco é chamado passo
recursivo, que é quando chamamos a
mesma função dentro dela. Veja, estamos
passando a variável a por valor. Logo,
vamos jogar novamente a letra c para a
função.
c
a
&3399uiop
c
Muito importante lembrar que,
quando uma função termina o seu
escopo, tudo que está dentro dela
é destruído. Portanto a caixinha a
será destruída e recriada,
possivelmente em um novo
endereço.
Vamos ver um exemplo
void exemplo(char a){
printf(“%c”, a);
exemplo(a);
}
3
4
5
Passo 3: Uma nova caixinha (variável) de
nome a será criada e armazenará o valor
que passamos na chamada da função.
c
a
&3633uiop
c
Provavelmente esta nova
caixinha terá um novo
endereço. A memória é
bastante aleatória.
Vamos ver um exemplo
void exemplo(char a){
printf(“%c”, a);
exemplo(a);
}
3
4
5
Passo 4: Imprimimos novamente a letra c
na tela.
cc
Vamos ver um exemplo
void exemplo(char a){
printf(“%c”, a);
exemplo(a);
}
3
4
5
Passo 5: Chamamos novamente a nossa
função. Outro passo recursivo. E tudo
recomeça outra vez.
c
a
&3633uiop
c
Vamos ver um exemplo
void exemplo(char a){
printf(“%c”, a);
exemplo(a);
}
3
4
5
Passo 3: Uma nova caixinha (variável) de
nome a será criada e armazenará o valor
que passamos na chamada da função.
c
a
&456guiop
c
Provavelmente esta nova
caixinha terá um novo
endereço. A memória é
bastante aleatória.
Vamos ver um exemplo
void exemplo(char a){
printf(“%c”, a);
exemplo(a);
}
3
4
5
Passo 4: Imprimimos novamente a letra c
na tela.
ccc
Vamos ver um exemplo
void exemplo(char a){
printf(“%c”, a);
exemplo(a);
}
3
4
5
Passo 5: Chamamos novamente a nossa
função. Outro passo recursivo. E tudo
recomeça outra vez.
c
a
&3633uiop
c
Recursividade
CHEGAAAAAA! UFF! Como fazer a recursão parar?
Pois é, esta é outra característica de uma função
recursiva. Ela precisa sempre ter um Caso Base, que
vai determinar quando ela vai parar de se chamar.
Caso base
void exemplo(char a){
printf(“%c”, a);
exemplo(a);
}
Para esta função, nem conseguiríamos criar um
caso base sem que tivéssemos mais um
parâmetro, que frequentemente é o contador dos
passos recursivos. Esse contador sempre é
diminuído por um fator qualquer (depende do
nosso problema) até que ele encontre um caso
base.
Esta característica torna a recursão, uma
resolução de problemas por instâncias menores
do mesmo problema.
A cada passo recursivo, o nosso problema
diminui, até que cheguemos no caso base, que
será a menor instância do nosso problema.
Caso base
void exemplo(char a){
printf(“%c”, a);
exemplo(a);
}
É muito importante
modelar a função recursiva
de maneira correta, pois
senão, como vimos, nosso
programa pode entrar em
loop e nunca parar!
Funções recursivas
Vamos ver um exemplo prático agora. Seja o fatorial matemático
definido por n!:
1! = 1
2! = 2*1 = 2*1!
3! = 3*2*1 = 3*2!
4! = 4*3*2*1 = 4*3!
5! = 5*4*3*2*1 = 5*4!
.....................................
n! = n*(n-1)*(n-2)*...*(1) = n*(n-1)!
Para criar uma função recursiva que
resolva este problema, precisamos
encontrar dois elementos essenciais
para a recursão:
1) Caso base
2) Passo recursivo
Funções recursivas
Vamos ver um exemplo prático agora. Seja o fatorial matemático
definido por n!:
1! = 1
2! = 2*1 = 2*1!
3! = 3*2*1 = 3*2!
4! = 4*3*2*1 = 4*3!
5! = 5*4*3*2*1 = 5*4!
.....................................
n! = n*(n-1)*(n-2)*...*(1) = n*(n-1)!
O caso base é muito simples, e
logicamente que é 1. Se olharmos para
todas as linhas, elas sempre terminam
no 1 e por isso ele é o nosso caso base.
Pense no caso base, como o elemento
que sempre vai ser atingindo em algum
momento e ele deve ser, pois do
contrário como vamos parar a recursão?
Funções recursivas
Vamos ver um exemplo prático agora. Seja o fatorial matemático
definido por n!:
1! = 1
2! = 2*1 = 2*1!
3! = 3*2*1 = 3*2!
4! = 4*3*2*1 = 4*3!
5! = 5*4*3*2*1 = 5*4!
.....................................
n! = n*(n-1)*(n-2)*...*(1) = n*(n-1)!
O passo recursivo é aquele em que
diminuímos a instância do nosso
problema por algum fator. Para o nosso
caso ele é dado pela nossa fórmula geral:
n*(n-1)!
Vamos entender o por que.
Funções recursivas
Vamos ver um exemplo prático agora. Seja o fatorial matemático
definido por n!:
1! = 1
2! = 2*1 = 2*1!
3! = 3*2*1 = 3*2!
4! = 4*3*2*1 = 4*3!
5! = 5*4*3*2*1 = 5*4!
.....................................
n! = n*(n-1)*(n-2)*...*(1) = n*(n-1)!
n*(n-1)! nos diz o seguinte:
Multiplique a instância do meu problema de
valor n por uma nova instância de valor n-1.
Para encontrarmos o valor da instância n-1
vamos ter que realizar novamente o fatorial.
Percebe que utilizamos o fatorial novamente
para calcular (n-1)!. Com certeza este é o nosso
passo recursivo, pois a cada chamada, vamos
diminuir a instância do nosso problema por um
fator de 1.
Funções recursivas
Nossa função então ficaria da seguinte maneira:
int fatorial(int n){
}
A função tem que
retornar um inteiro, pois é
o valor do fatorial que
queremos encontrar!
Funções recursivas
Nossa função então ficaria da seguinte maneira:
int fatorial(int n){
if( n == 1 )
return 1;
}
Sempre numa função recursiva,
a primeira coisa a fazer é
colocar o caso base. Sabemos
que o fatorial de 1 é 1 e então
este será o nosso valor de
retorno.
Funções recursivas
Nossa função então ficaria da seguinte maneira:
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
Agora então definimos nosso
passo recursivo, dado pela
fórmula geral. O passo recursivo
é exatamente a nossa fórmula
geral, porém escrito na
linguagem de programação e
não numa fórmula matemática.
E nossa função recursiva está
pronta! Vamos testá-la.
Funções recursivas
Vamos assumir que chamamos esta função na main e passamos o valor 3 na chamada.
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
3
1
2
3
4
Passo 1: uma caixinha para n é
criada e o valor 3 colocado lá
dentro.
3
n
&3633uiop
Funções recursivas
Vamos assumir que chamamos esta função na main e passamos o valor 3 na chamada.
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
1
2
3
4
Passo 2: verificamos se atingimos
nosso caso base. Como n não é
igual a 1, ainda não o atingimos.
Pulamos então para o passo 4.
3
n
&3633uiop
Funções recursivas
Vamos assumir que chamamos esta função na main e passamos o valor 3 na chamada.
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
1
2
3
4
Passo 4: Passo recursivo. Vamos
chamar nossa função novamente
passando um novo valor de n.
3
n
&3633uiop
2
Funções recursivas
Vamos assumir que chamamos esta função na main e passamos o valor 3 na chamada.
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
5
6
7
8
Passo 5: Uma nova caixinha para n
é criada e o valor de chamada é
atribuído à ela.
2
n
&2223uiop
2
Funções recursivas
Vamos assumir que chamamos esta função na main e passamos o valor 3 na chamada.
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
5
6
7
8
Passo 6: Verificamos novamente o
nosso caso base. Ainda não o
atingimos, e então o passo 7 será
pulado.
2
n
&2223uiop
Funções recursivas
Vamos assumir que chamamos esta função na main e passamos o valor 3 na chamada.
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
5
6
7
8
Passo 8: Uma nova chamada
recursiva é realizada com uma
instância ainda menor do
problema.
2
n
&2223uiop
1
Funções recursivas
Vamos assumir que chamamos esta função na main e passamos o valor 3 na chamada.
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
9
10
11
12
Passo 9: Novamente uma nova
caixinha para n é criada, e o valor
passado na chamada é atribuído
para ela.
1
n
&9923uiop
1
Funções recursivas
Vamos assumir que chamamos esta função na main e passamos o valor 3 na chamada.
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
9
10
11
12
Passo 10: Verificamos o nosso caso
base e percebemos que acabamos
de atingí-lo! Então o passo 12 não
será executado.
1
n
&9923uiop
1
Funções recursivas
Vamos assumir que chamamos esta função na main e passamos o valor 3 na chamada.
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
9
10
11
12
Passo 11: Mas e agora,
encontramos a palavra
return, para onde temos
que retornar? Para a
main?
1
n
&9923uiop
Recursividade
Entender para onde voltar quando atingimos o caso
base é essencial para conseguirmos entender o que
é recursividade. Vamos ver uma mapa desta
execução.
Recursividade
Na primeira chamada tínhamos o seguinte passo
recursivo:
1) 3 * fatorial(3-1)
Recursividade
Na segunda chamada:
1) 3 * fatorial(3-1)
2) 2 * fatorial(2-1)
Recursividade
Na terceira chamada:
1) return 3 * fatorial(3-1)
2) return 2 * fatorial(2-1)
3) return 1
A terceira chamada foi onde encontramos o nosso
caso base. Dessa maneira, o valor de retorno da
chamada em que o caso base é encontrado deve ser
retornado para exatamente a última chamada
efetuada antes do caso base.
Perceba que todas as chamadas são também
retornos e mais uma vez, um retorno só pode conter
valores já definidos. O que acontece nas chamadas 2
e 3, é que elas estão esperando valores de retorno
para poderem realizar a multiplicação. Já na chamada
3 não, 1 já é um valor definido e não tem que realizar
nenhuma operação.
Recursividade
Logo:
1) return 3 * fatorial(3-1)
2) return 2 * fatorial(2-1)
3) return 1
1
Recursividade
Logo:
1) return 3 * fatorial(3-1)
2) return 2 *
3) return 1
1
Agora a chamada 2 pode realizar a
multiplicação e retornar seu valor
para a chamada 1.
Recursividade
Logo:
1) return 3 * fatorial(3-1)
2) return 2
3) return 1
2
Recursividade
Logo:
1) return 3 *
2) return 2
3) return 1
2
Por fim, a chamada 3 pode realizar
também a multiplicação e retornar
para onde foi chamada. Como vimos
no começo, assumimos que chamamos
a função fatorial na main e então é pra
lá que o retorno da primeira chamada
irá voltar, devolvendo enfim o valor do
fatorial de 3 que é 6!
Recursividade
Logo:
1) return 6
2) return 2
3) return 1
6
Assim se encerra a nossa função
recursiva!
Finalizando a execução
Vamos assumir que chamamos esta função na main e passamos o valor 3 na chamada.
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
9
10
11
12
1
Funções recursivas
Vamos assumir que chamamos esta função na main e passamos o valor 3 na chamada.
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
5
6
7
8
2
Funções recursivas
Vamos assumir que chamamos esta função na main e passamos o valor 3 na chamada.
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
1
2
3
4
2
6
Voltando pra main com 6!
Funções recursivas
Escreva uma função recursiva que retorne o valor de um número elevado por n.
Exemplo:
exp(4,2) -> significa que queremos elevar 4 ao quadrado.
Quem fizer este exercício e me explicar na sala, poderá errar um exercício no
mini-teste.

Recursividade

  • 1.
  • 2.
    Recursividade Muitos algoritmos têma seguinte propriedade: cada instância do problema contém uma instância menor do mesmo problema. Dizemos que esses problemas têm estrutura recursiva, porque é possível resolver o problema chamando à si mesmo com uma instância menor do problema.
  • 3.
    Recursividade Uma função quechama à si mesmo é dita recursiva.
  • 4.
    Funções que chamamoutras funções Esse conceito tem que ficar bem claro: Uma função pode chamar uma outra ou mais funções. Vamos ver um exemplo.
  • 5.
    Calcular a mesada Suponhaque queremos um programa para calcular a mesada de nossos filhos, baseado em suas idades e notas. Seja então a seguinte função calcMesada. Não se preocupem com a main, ela logo aparecerá. Não precisamos criar a main primeiro sempre, mas ela terá que ser criada em algum momento! O que esta função faz é receber um parâmetro que será a idade do nosso filho e retorna um valor maior da mesada para filhos maiores de idade.
  • 6.
    Calcular a mesada Digamosagora que, a mesada de nossos filhos menores de idade, tem que ser recompensada (ou não!) por suas notas. Então criamos a seguinte função que dá um bônus ou um desconto (bd) para nosso filho menor de idade. Essa função recebe três parâmetros: a idade, a nota e o valor da mesada já calculada pela função anterior. Por isso é muito importante chamar as funções na ordem em que queremos os resultados. Se não calcularmos a mesada antes com a outra função, como vamos passa-la como parâmetro aqui!?Se a idade do nosso filho for menor que 18, vamos variar a mesada de acordo com a nota dele, senão, vamos somente retornar o mesmo valor da mesada que passamos para a função.
  • 7.
    Calcular a mesada Namain, vamos receber o valor da idade e a nota através da função scanf (permite que o usuário digite valores e armazena nas variáveis passada como parâmetro). Após isso, chamamos a função calcMesada para calcular a mesada e atribuímos este valor a variável mesada. Agora vamos chamar a nossa segunda função e passando como parâmetro a própria mesada obtida anteriormente.
  • 8.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 8 ? ? ?
  • 9.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 8 ? ? ? Passo 1: variável mesada é criada sem valor algum por enquanto. mesada &43jjuiop
  • 10.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 8 ? ? ? Passo 2: variável idade é criada sem valor algum por enquanto. mesada &43jjuiop idade &4399uiop
  • 11.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 8 ? ? ? Passo 3: variável nota é criada sem valor algum por enquanto. mesada &43jjuiop idade &4399uiop nota &43666iop
  • 12.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 8 ? ? ? Passo 4: mensagem exibida na tela: Entre com a idade do seu filho:
  • 13.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 8 ? ? ? Passo 5: o usuário digita um valor para idade e esse valor vai para a variável idade. Entre com a idade do seu filho: 10 10 idade &4399uiop
  • 14.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 8 ? ? ? Passo 6: mensagem é exibida na tela Entre com a idade do seu filho: 10 Entre com a nota geral do seu filho:
  • 15.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 8 ? ? ? Passo 7: o usuário entra com o valor da nota e esse valor vai direto para a variável nota. Entre com a idade do seu filho: 10 Entre com a nota geral do seu filho: 1 1 nota &43666iop
  • 16.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 8 ? ? ? Vamos para a função! A seta está para cima porque uma função que é chamada por outra função sempre deve ser declarada acima da função que à está chamando. Do contrário, a função não conseguirá chama- la! 10 Estamos passando o valor da idade e não uma referência. Por isso nossa caixinha só tem um valor e nada de referências para a variável idade. (Recebemos este valor anteriormente!)
  • 17.
    Vamos executar esteprograma int calcMesada(int idade){ if(idade < 18) return idade*20; else { return idade*50; } } Passo 9: Uma nova caixinha (varíavel) chamada idade é criada e o valor que “jogamos” (passamos como parâmetro na chamada da função) para a função é colocado lá dentro. 10 9 10 11 12 13 14 10 idade &9999uiop Muito importante entender aqui que essa caixinha tem o mesmo nome que a caixinha da idade que está na main. Mas como pode ser visto os endereços são diferentes. ELAS NÃO SÃO A MESMA VARIÁVEL, SOMENTE TEM O MESMO NOME. Já sabemos que não podemos ter duas variáveis com o mesmo nome, mas esta regra é válida para mesmas funções. Funções diferentes podem ter variáveis com mesmo nome, que é o nosso caso! Lembre-se, uma função não consegue ver nada que está dentro de outra função. O escopo de uma função é digamos “secreto” para todas as outras!
  • 18.
    Vamos executar esteprograma int calcMesada(int idade){ if(idade < 18) return idade*20; else { return idade*50; } } Passo 10: Verificamos se a idade é menor que 18. Para este nosso caso ela é, então o passo 11 será executado! 9 10 11 12 13 14 10 idade &9999uiop Lembre-se, uma função não consegue ver nada que está dentro de outra função. O escopo de uma função é digamos “secreto” para todas as outras!
  • 19.
    Vamos executar esteprograma int calcMesada(int idade){ if(idade < 18) return idade*20; else { return idade*50; } } Passo 11: Encontramos a palavra return. Portanto neste momento vamos retornar o valor da multiplicação de idade por 20 para o local onde esta função foi chamada. Neste caso é a na main.9 10 11 12 13 10 idade &9999uiop Importante: os passos 12, 13 nunca serão executados, pois uma vez que em uma função, é encontrado a palavra de retorno, ela imediatamente interrompe sua execução e retorna o valor passado para o return. 200 Só podemos retornar valores que já temos. Por isso, o retorno para a main só vai acontecer quando o computador processar a operação idade*20 e substituir o valor desta multiplicação na expressão. Se o computador demorasse 10 anos para computar esta multiplicação, então demoraríamos 10 anos para voltar para a main!
  • 20.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 812 ? ? Passo 12: a caixinha de mesada recebe o valor de retorno da função. 13 200 mesada &43jjuiop 200
  • 21.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 812 ? ? Passo 13: vamos novamente para outra função. Chamamos bdMesada enviando os valores dos nossos três parâmetros! (Passagem por valor!) 13 200 mesada &43jjuiop 10 idade &4399uiop 1 nota &43666iop 10 1 200
  • 22.
    Vamos executar esteprograma int bdMesada(int idade, int notas, int mesada){ if(idade < 18) return mesada*notas; return mesada; } Passo 14: São criadas novas caixinhas para os nossos parâmetros que vão receber os valores enviados na chamada da função, na mesma ordem enviada. 14 15 16 17 Lembre-se, uma função não consegue ver nada que está dentro de outra função. O escopo de uma função é digamos “secreto” para todas as outras! 200 mesada &99yjuiop 10 idade &4oouiop 1 nota &4wertiop MESMOS NOMES, MAS ENDEREÇOS DIFERENTES! 10 1 200
  • 23.
    Vamos executar esteprograma int bdMesada(int idade, int notas, int mesada){ if(idade < 18) return mesada*notas; return mesada; } Passo 15: Vamos ver se a idade é menor que 18. Para o nosso caso é, então vamos executar o passo 16. 14 15 16 17 Lembre-se, uma função não consegue ver nada que está dentro de outra função. O escopo de uma função é digamos “secreto” para todas as outras! 200 mesada &99yjuiop 10 idade &4oouiop 1 nota &4wertiop MESMOS NOMES, MAS ENDEREÇOS DIFERENTES!
  • 24.
    Vamos executar esteprograma int bdMesada(int idade, int notas, int mesada){ if(idade < 18) return mesada*notas; return mesada; } Passo 16: Encontramos a palavra return e então vamos retornar para o local que esta função foi chamada, retornando o valor de mesada*notas que para nosso caso é 200*1 = 200. O passo 17 então não será executado, pois interrompemos a execução no momento do retorno. 14 15 16 17 Lembre-se, uma função não consegue ver nada que está dentro de outra função. O escopo de uma função é digamos “secreto” para todas as outras! 200 mesada &99yjuiop 10 idade &4oouiop 1 nota &4wertiop 200 Novamente, retornamos valores e nunca expressões! Para que a função retorne para onde foi chamada, o computador primeiro tem que fazer a multiplicação e devolver um valor para o retorno!
  • 25.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 812 15 16 Passo 14: a caixinha da mesada, vai receber o valor de retorno da função. Como já tínhamos um valor lá, ele será substituído pelo novo. Coincidentemente, este valor é o mesmo, porque nossa multiplicação na função foi por 1. De qualquer maneira o valor será substituído, mesmo que seja pelo mesmo valor! 13 10 idade &4399ui 1 nota &43666iop 14 200 200 mesada &43jjuiop 200
  • 26.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 812 15 16 Passo 15: É exibida uma mensagem na tela com o valor da variável mesada, que é a saída final do nosso programa e o objetivo que queríamos atingir. 1314 200 Entre com a idade do seu filho: 10 Entre com a nota geral do seu filho: 1 O valor da mesada para seu filho e: 200.
  • 27.
    Vamos executar esteprograma int main(){ int mesada; int idade; int nota; printf("Entre com a idade do seu filho:"); scanf("%d", &idade); printf("Entre com a nota geral do seu filho:"); scanf("%d", &nota); mesada = calcMesada(idade); mesada = bdMesada(idade,nota,mesada); printf("nnO valor da mesada para seu filho e: %d", mesada); return 0; } 1 2 3 4 5 6 7 812 15 16 Passo 16: Programa termina. É exibida na tela uma mensagem padrão da linguagem. 1314 200 Entre com a idade do seu filho: 10 Entre com a nota geral do seu filho: 1 O valor da mesada para seu filho e: 200. Program returned with execution of 0.2222s
  • 28.
    Recursividade Como já vimosque uma função pode chamar uma ou mais funções, então não há porque duvidar que uma função pode chamar à ela mesma! Vamos ver como funciona então uma função recursiva.
  • 29.
    Vamos ver umexemplo int main(){ exemplo(‘c’); return 0; } void exemplo(char a){ printf(“%c”, a); exemplo(a); } Digamos que temos a função exemplo e chamamos ela na main passando o caracter ‘c’. Vamos ver como será a execução. 1 2 3 4 5 ?
  • 30.
    Vamos ver umexemplo int main(){ exemplo(‘c’); return 0; } 1 2 ? Passo 1: o programa se inicia.
  • 31.
    Vamos ver umexemplo int main(){ exemplo(‘c’); return 0; } 1 2 ? Passo 2: vamos para a função e estamos passando o caracter ‘c’ utilizando passagem por valor. Dessa vez nem mesmo temos variáveis na main. Só estamos querendo chamar a função para ver o qual é seu comportamento recursivo. c
  • 32.
    Vamos ver umexemplo void exemplo(char a){ printf(“%c”, a); exemplo(a); } 3 4 5 Passo 3: Uma variável (caixinha) do tipo char é criada e o valor passado na chamada da função é atribuído à ela. c c a &3399uiop
  • 33.
    Vamos ver umexemplo void exemplo(char a){ printf(“%c”, a); exemplo(a); } 3 4 5 Passo 4: Imprimimos o caracter que está na variável a na tela. c a &3399uiop c
  • 34.
    Vamos ver umexemplo void exemplo(char a){ printf(“%c”, a); exemplo(a); } 3 4 5 Passo 5: O passo cinco é chamado passo recursivo, que é quando chamamos a mesma função dentro dela. Veja, estamos passando a variável a por valor. Logo, vamos jogar novamente a letra c para a função. c a &3399uiop c Muito importante lembrar que, quando uma função termina o seu escopo, tudo que está dentro dela é destruído. Portanto a caixinha a será destruída e recriada, possivelmente em um novo endereço.
  • 35.
    Vamos ver umexemplo void exemplo(char a){ printf(“%c”, a); exemplo(a); } 3 4 5 Passo 3: Uma nova caixinha (variável) de nome a será criada e armazenará o valor que passamos na chamada da função. c a &3633uiop c Provavelmente esta nova caixinha terá um novo endereço. A memória é bastante aleatória.
  • 36.
    Vamos ver umexemplo void exemplo(char a){ printf(“%c”, a); exemplo(a); } 3 4 5 Passo 4: Imprimimos novamente a letra c na tela. cc
  • 37.
    Vamos ver umexemplo void exemplo(char a){ printf(“%c”, a); exemplo(a); } 3 4 5 Passo 5: Chamamos novamente a nossa função. Outro passo recursivo. E tudo recomeça outra vez. c a &3633uiop c
  • 38.
    Vamos ver umexemplo void exemplo(char a){ printf(“%c”, a); exemplo(a); } 3 4 5 Passo 3: Uma nova caixinha (variável) de nome a será criada e armazenará o valor que passamos na chamada da função. c a &456guiop c Provavelmente esta nova caixinha terá um novo endereço. A memória é bastante aleatória.
  • 39.
    Vamos ver umexemplo void exemplo(char a){ printf(“%c”, a); exemplo(a); } 3 4 5 Passo 4: Imprimimos novamente a letra c na tela. ccc
  • 40.
    Vamos ver umexemplo void exemplo(char a){ printf(“%c”, a); exemplo(a); } 3 4 5 Passo 5: Chamamos novamente a nossa função. Outro passo recursivo. E tudo recomeça outra vez. c a &3633uiop c
  • 41.
    Recursividade CHEGAAAAAA! UFF! Comofazer a recursão parar? Pois é, esta é outra característica de uma função recursiva. Ela precisa sempre ter um Caso Base, que vai determinar quando ela vai parar de se chamar.
  • 42.
    Caso base void exemplo(chara){ printf(“%c”, a); exemplo(a); } Para esta função, nem conseguiríamos criar um caso base sem que tivéssemos mais um parâmetro, que frequentemente é o contador dos passos recursivos. Esse contador sempre é diminuído por um fator qualquer (depende do nosso problema) até que ele encontre um caso base. Esta característica torna a recursão, uma resolução de problemas por instâncias menores do mesmo problema. A cada passo recursivo, o nosso problema diminui, até que cheguemos no caso base, que será a menor instância do nosso problema.
  • 43.
    Caso base void exemplo(chara){ printf(“%c”, a); exemplo(a); } É muito importante modelar a função recursiva de maneira correta, pois senão, como vimos, nosso programa pode entrar em loop e nunca parar!
  • 44.
    Funções recursivas Vamos verum exemplo prático agora. Seja o fatorial matemático definido por n!: 1! = 1 2! = 2*1 = 2*1! 3! = 3*2*1 = 3*2! 4! = 4*3*2*1 = 4*3! 5! = 5*4*3*2*1 = 5*4! ..................................... n! = n*(n-1)*(n-2)*...*(1) = n*(n-1)! Para criar uma função recursiva que resolva este problema, precisamos encontrar dois elementos essenciais para a recursão: 1) Caso base 2) Passo recursivo
  • 45.
    Funções recursivas Vamos verum exemplo prático agora. Seja o fatorial matemático definido por n!: 1! = 1 2! = 2*1 = 2*1! 3! = 3*2*1 = 3*2! 4! = 4*3*2*1 = 4*3! 5! = 5*4*3*2*1 = 5*4! ..................................... n! = n*(n-1)*(n-2)*...*(1) = n*(n-1)! O caso base é muito simples, e logicamente que é 1. Se olharmos para todas as linhas, elas sempre terminam no 1 e por isso ele é o nosso caso base. Pense no caso base, como o elemento que sempre vai ser atingindo em algum momento e ele deve ser, pois do contrário como vamos parar a recursão?
  • 46.
    Funções recursivas Vamos verum exemplo prático agora. Seja o fatorial matemático definido por n!: 1! = 1 2! = 2*1 = 2*1! 3! = 3*2*1 = 3*2! 4! = 4*3*2*1 = 4*3! 5! = 5*4*3*2*1 = 5*4! ..................................... n! = n*(n-1)*(n-2)*...*(1) = n*(n-1)! O passo recursivo é aquele em que diminuímos a instância do nosso problema por algum fator. Para o nosso caso ele é dado pela nossa fórmula geral: n*(n-1)! Vamos entender o por que.
  • 47.
    Funções recursivas Vamos verum exemplo prático agora. Seja o fatorial matemático definido por n!: 1! = 1 2! = 2*1 = 2*1! 3! = 3*2*1 = 3*2! 4! = 4*3*2*1 = 4*3! 5! = 5*4*3*2*1 = 5*4! ..................................... n! = n*(n-1)*(n-2)*...*(1) = n*(n-1)! n*(n-1)! nos diz o seguinte: Multiplique a instância do meu problema de valor n por uma nova instância de valor n-1. Para encontrarmos o valor da instância n-1 vamos ter que realizar novamente o fatorial. Percebe que utilizamos o fatorial novamente para calcular (n-1)!. Com certeza este é o nosso passo recursivo, pois a cada chamada, vamos diminuir a instância do nosso problema por um fator de 1.
  • 48.
    Funções recursivas Nossa funçãoentão ficaria da seguinte maneira: int fatorial(int n){ } A função tem que retornar um inteiro, pois é o valor do fatorial que queremos encontrar!
  • 49.
    Funções recursivas Nossa funçãoentão ficaria da seguinte maneira: int fatorial(int n){ if( n == 1 ) return 1; } Sempre numa função recursiva, a primeira coisa a fazer é colocar o caso base. Sabemos que o fatorial de 1 é 1 e então este será o nosso valor de retorno.
  • 50.
    Funções recursivas Nossa funçãoentão ficaria da seguinte maneira: int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } Agora então definimos nosso passo recursivo, dado pela fórmula geral. O passo recursivo é exatamente a nossa fórmula geral, porém escrito na linguagem de programação e não numa fórmula matemática. E nossa função recursiva está pronta! Vamos testá-la.
  • 51.
    Funções recursivas Vamos assumirque chamamos esta função na main e passamos o valor 3 na chamada. int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } 3 1 2 3 4 Passo 1: uma caixinha para n é criada e o valor 3 colocado lá dentro. 3 n &3633uiop
  • 52.
    Funções recursivas Vamos assumirque chamamos esta função na main e passamos o valor 3 na chamada. int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } 1 2 3 4 Passo 2: verificamos se atingimos nosso caso base. Como n não é igual a 1, ainda não o atingimos. Pulamos então para o passo 4. 3 n &3633uiop
  • 53.
    Funções recursivas Vamos assumirque chamamos esta função na main e passamos o valor 3 na chamada. int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } 1 2 3 4 Passo 4: Passo recursivo. Vamos chamar nossa função novamente passando um novo valor de n. 3 n &3633uiop 2
  • 54.
    Funções recursivas Vamos assumirque chamamos esta função na main e passamos o valor 3 na chamada. int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } 5 6 7 8 Passo 5: Uma nova caixinha para n é criada e o valor de chamada é atribuído à ela. 2 n &2223uiop 2
  • 55.
    Funções recursivas Vamos assumirque chamamos esta função na main e passamos o valor 3 na chamada. int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } 5 6 7 8 Passo 6: Verificamos novamente o nosso caso base. Ainda não o atingimos, e então o passo 7 será pulado. 2 n &2223uiop
  • 56.
    Funções recursivas Vamos assumirque chamamos esta função na main e passamos o valor 3 na chamada. int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } 5 6 7 8 Passo 8: Uma nova chamada recursiva é realizada com uma instância ainda menor do problema. 2 n &2223uiop 1
  • 57.
    Funções recursivas Vamos assumirque chamamos esta função na main e passamos o valor 3 na chamada. int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } 9 10 11 12 Passo 9: Novamente uma nova caixinha para n é criada, e o valor passado na chamada é atribuído para ela. 1 n &9923uiop 1
  • 58.
    Funções recursivas Vamos assumirque chamamos esta função na main e passamos o valor 3 na chamada. int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } 9 10 11 12 Passo 10: Verificamos o nosso caso base e percebemos que acabamos de atingí-lo! Então o passo 12 não será executado. 1 n &9923uiop 1
  • 59.
    Funções recursivas Vamos assumirque chamamos esta função na main e passamos o valor 3 na chamada. int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } 9 10 11 12 Passo 11: Mas e agora, encontramos a palavra return, para onde temos que retornar? Para a main? 1 n &9923uiop
  • 60.
    Recursividade Entender para ondevoltar quando atingimos o caso base é essencial para conseguirmos entender o que é recursividade. Vamos ver uma mapa desta execução.
  • 61.
    Recursividade Na primeira chamadatínhamos o seguinte passo recursivo: 1) 3 * fatorial(3-1)
  • 62.
    Recursividade Na segunda chamada: 1)3 * fatorial(3-1) 2) 2 * fatorial(2-1)
  • 63.
    Recursividade Na terceira chamada: 1)return 3 * fatorial(3-1) 2) return 2 * fatorial(2-1) 3) return 1 A terceira chamada foi onde encontramos o nosso caso base. Dessa maneira, o valor de retorno da chamada em que o caso base é encontrado deve ser retornado para exatamente a última chamada efetuada antes do caso base. Perceba que todas as chamadas são também retornos e mais uma vez, um retorno só pode conter valores já definidos. O que acontece nas chamadas 2 e 3, é que elas estão esperando valores de retorno para poderem realizar a multiplicação. Já na chamada 3 não, 1 já é um valor definido e não tem que realizar nenhuma operação.
  • 64.
    Recursividade Logo: 1) return 3* fatorial(3-1) 2) return 2 * fatorial(2-1) 3) return 1 1
  • 65.
    Recursividade Logo: 1) return 3* fatorial(3-1) 2) return 2 * 3) return 1 1 Agora a chamada 2 pode realizar a multiplicação e retornar seu valor para a chamada 1.
  • 66.
    Recursividade Logo: 1) return 3* fatorial(3-1) 2) return 2 3) return 1 2
  • 67.
    Recursividade Logo: 1) return 3* 2) return 2 3) return 1 2 Por fim, a chamada 3 pode realizar também a multiplicação e retornar para onde foi chamada. Como vimos no começo, assumimos que chamamos a função fatorial na main e então é pra lá que o retorno da primeira chamada irá voltar, devolvendo enfim o valor do fatorial de 3 que é 6!
  • 68.
    Recursividade Logo: 1) return 6 2)return 2 3) return 1 6 Assim se encerra a nossa função recursiva!
  • 69.
    Finalizando a execução Vamosassumir que chamamos esta função na main e passamos o valor 3 na chamada. int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } 9 10 11 12 1
  • 70.
    Funções recursivas Vamos assumirque chamamos esta função na main e passamos o valor 3 na chamada. int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } 5 6 7 8 2
  • 71.
    Funções recursivas Vamos assumirque chamamos esta função na main e passamos o valor 3 na chamada. int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } 1 2 3 4 2 6 Voltando pra main com 6!
  • 72.
    Funções recursivas Escreva umafunção recursiva que retorne o valor de um número elevado por n. Exemplo: exp(4,2) -> significa que queremos elevar 4 ao quadrado. Quem fizer este exercício e me explicar na sala, poderá errar um exercício no mini-teste.