Você está na página 1de 56

Recursividade

Sumário

● O que é recursão
● Forma Recursiva

● Passos na recursão
○ Processamento

○ Chamada da função
Dividir para conquistar

● Muitas vezes, precisamos dividir um problema em subproblemas menores


○ Fica até mais fácil de resolver!

○ Exemplos:

■ Computação gráfica: BSP

■ Travessia em árvores
Recursão

● É um conceito geral (independe da computação)


○ Letras: GNU, Allegro (Allegro Low-Level Game Routines)
○ Matemática
○ Artes: música, pintura

● É a definição da solução de um problema em função de uma instância


menor dele mesmo!
Exemplo de definição recursiva

● Fatorial de um número:
○ 5! = 5*4*3*2*1

○ 4! = 4*3*2*1

○ 5! = 5*4!

● Podemos dizer que fatorial(n) = n*fatorial(n-1)!


Forma Recursiva

● A recursão precisa de três elementos base:


○ Caso base ou condição de parada

○ Processamento a cada etapa

○ Chamada recursiva
Exemplo
int main(){
int n;
scanf(“%d”, &n);
printf(“%d\n”, fatorial(n));
return 0;
}
Exemplo
int fatorial(int n){ int main(){
if(n == 1 || n == 0) int n;
return 1; scanf(“%d”, &n);
else printf(“%d\n”, fatorial(n));
return n*fatorial(n-1); return 0;
} }
Exemplo
int fatorial(int n){ int main(){
if(n == 1 || n == 0) int n;
return 1; scanf(“%d”, &n);
else printf(“%d\n”, fatorial(n));
return n*fatorial(n-1); return 0;
} }

● Condição de Parada
● Processamento
● Chamada recursiva
Exemplo
int fatorial(int n){ int main(){
if(n == 1 || n == 0) int n;
return 1; scanf(“%d”, &n);
else printf(“%d\n”, fatorial(n));
return n*fatorial(n-1); return 0;
} }

● Condição de Parada IMPORTANTE!!!!


● Processamento A cada chamada recursiva, o algoritmo deve se aproximar da
● Chamada recursiva condição de parada!
Recursividade x Iteratividade

● Muitas vezes, a forma recursiva é mais natural para abordamos um


problema
○ Série de Fibonacci
Fibonacci Iterativo

#include <stdio.h>
int main( void )
{
int i, j, n, fib;
scanf( "%i", &n );
fib = 0;
j = 1;
for(i=1; i<n; i++)
{
j = fib + j;
fib = j - fib;
}
printf(“%d\n”, fib);
return 0;
}
Fibonacci Recursivo
int fib( int x )
{
if( x <= 1 )
return x;
else
return fib(x-1) + fib(x-2);
}

int main(){
int n;
scanf(“%d”, &n);

printf(“%d\n”, fib(n));
return 0;
}
Explorando as possibilidades

● A recursão pode ser usada como procedimento

● Normalmente usamos recursão quando queremos explorar todas as


possibilidades de um problema
○ Backtracking
Backtracking
Sudoku
Sudoku - solução
Exemplos simples de recursão

● Multiplicação

● Fatorial

● Potência
Processamento

● O processamento de informações pode ocorrer:


○ antes da chamada recursiva (pré-processamento)

○ após a chamada recursiva (pós-processamento)

● Uma recursão que faz todo o processamento antes da


chamada recursiva é uma recursão em cauda (similar a
um loop)
Exemplo - Conversão de Base

● Faça um programa que converta um número da base decimal para a base


binária utilizando a recursividade.

● Para converter um número de decimal para binário, fazemos sucessivas


divisões por 2 e guardamos o resto (0 ou 1)
○ Ex: 15 = 1111
Solução Recursiva

● Para n = 10
○ 10 / 2 = 5 (Resto 0)

○ 5 / 2 = 2 (Resto 1)

○ 2 /2 = 1 (Resto 0)

○ 1 / 2 = 0 (Resto 1)

● O valor binário é a ordem invertida dos restos: 1010


Solução Recursiva

● A divisão é um pré-processamento (você divide e então faz a chamada)

● A impressão é um pós-processamento (você só imprime o número após a


chamada da função retornar)
Solução Recursiva
#include <stdio.h> int main(){
int n;
void binario(int n){
if(n > 0){ scanf("%d", &n)
binario(n/2); binario(n);
printf("%d", n%2); printf("\n");
}
} return 0;
}
Recursão Mútua ou Indireta

● Uma recursão pode ser montada usando mais de uma função

● Nesse caso, a recursão se dá quando um ciclo de chamadas é feito


○ Ex: função1 função2 função 1
Exemplo
int ehPar(int n){ int ehImpar(int n){
if(n == 0) if(n == 0)
return 0;
return 1;
else
else return ehPar(n-1);
return ehImpar(n-1); }
}
Problema 01

● Dado um labirinto, descubra se é possível sair da


posição inicial e chegar em uma determinada posição
final.
● Seu programa lerá um mapa NxN (N <= 40). Cada
posição do mapa será representado por um valor inteiro,
0 sendo uma casa livre para andar e 1 sendo uma
barreira
● Verificar se a partir de uma posição inicial (x,y) é possível
chegar em uma posição final (x’, y’).
Maze Runner

● Seu programa lerá da entrada:


○ A dimensão do mapa N

○ NxN entradas, representando cada posição do labirinto

○ A posição inicial

○ A posição final desejada

● Seu programa deve imprimir “Freedom” se conseguir alcançar a posição, e


“Trapped” caso contrário.
Maze Runner
Maze Runner
Solução

● Vamos usar uma técnica mais avançada de programação


para resolver esse problema: uma função que explora
todas as possibilidades (backtracking), mas se lembra do
caminho que fez até o ponto em que está.

● Dessa forma iremos evitar que fiquemos presos em um


ciclo dentro do labirinto!
Solução - Função Principal
#include <stdio.h>
#include <string.h>
int main(){
int lab[40][40];
int percurso[40][40];
int n, ok, i, j;
int origx, origy, destx, desty;
memset(lab, 0, sizeof(lab));
memset(percurso, 0, sizeof(percurso));
Solução - Função Principal

scanf("%d", &n);
for(i=0; i<n; i++){
for(j=0; j<n; j++){
scanf("%d", &lab[i][j]);
}
}

scanf("%d %d", &origx, &origy);


scanf("%d %d", &destx, &desty);
Solução - Função Principal

ok = percorreLab(origx, origy, destx, desty, n-1, lab,


percurso);

if(ok)
printf("Freedom\n");
else
printf("Trapped\n");

return 0;
}
Função de Movimento - Caso Base

int percorreLab(int ox, int oy, int dx, int dy, int tam, int
mat[41][41], int path[41][41]){
int ok;

if(ox == dx && oy == dy)


return 1;
Testa o movimento para baixo

else{
if(ox < tam && mat[ox+1][oy] == 0 && path[ox+1][oy] ==
0){
path[ox+1][oy] = 1;
ok = percorreLab(ox+1, oy, dx, dy, tam, mat, path);
if(ok) return 1;
path[ox+1][oy] = 0;
}
Testa o movimento para direita

if(oy<tam && mat[ox][oy+1] == 0 && path[ox][oy+1] == 0){


path[ox][oy+1] = 1;
ok = percorreLab(ox, oy+1, dx, dy, tam, mat, path);
if(ok) return 1;
path[ox][oy+1] = 0;
}
Testa o movimento para esquerda

if(oy > 0 && mat[ox][oy-1] == 0 && path[ox][oy-1] == 0){


path[ox][oy-1] = 1;
ok = percorreLab(ox, oy-1, dx, dy, tam, mat, path);
if(ok) return 1;
path[ox][oy-1] = 0;
}
Testa o movimento para cima

if(ox > 0 && mat[ox-1][oy] == 0 && path[ox-1][oy] == 0){


path[ox-1][oy] = 1;
ok = percorreLab(ox-1, oy, dx, dy, tam, mat, path);
if(ok) return 1;
path[ox-1][oy] = 0;
}

return 0;
}
}
Dúvidas?
Problema 02

● Zoro é um grande espadachim, porém ele tem um


péssimo senso de direção! Isso faz com que ele
constantemente se perca dos outros e acabe indo parar
no lugar errado dos duelos.
Mapa do (T?)Zoro

● Preocupados que isso possa afetar a sua equipe, o


bando do Chapéu de Palha resolveu pedir que os alunos
de ITP fizessem um programa que ajudasse o Zoro a
achar os locais corretos das batalhas!
Zoro Total?

● Seu programa lerá quatro valores inteiros: a posição (x,y)


inicial de Zoro e a posição (x,y) onde a batalha acontece.

● Você deverá traçar um mapa para que o zoro chegue da


posição inicial até a posição final, imprimindo cada passo
que Zoro deve dar (senão, ele irá se perder)!
Exemplo de Entrada e Saída

● Entrada Saída

0050 Passa por (0,0)


Passa por (1,0)
Passa por (2,0)
Passa por (3,0)
Passa por (4,0)
Chega em (5,0)
Proposta de Solução

void caminho(int origx, int origy, int* destx, int* desty){


if(origx < 0 || origy < 0)
return;
else if(origx != *destx){
if(origx > *destx){
printf("Passa por (%d,%d)\n", origx, origy);
caminho(--origx, origy, destx, desty);
}
else{
printf("Passa por (%d,%d)\n", origx, origy);
caminho(++origx, origy, destx, desty);
}
}
Proposta de Solução

else if(origy != *desty){


if(origy > *desty){
printf("Passa por (%d,%d)\n", origx, origy);
caminho(origx, --origy, destx, desty);
}
else{
printf("Passa por (%d,%d)\n", origx, origy);
caminho(origx, ++origy, destx, desty);
}
}
else{
printf("Chega em (%d,%d)\n", origx, origy);
}}
Proposta de Solução

int main(){
int iniciox, inicioy;
int finalx, finaly;

scanf("%d %d %d %d", &iniciox, &inicioy, &finalx, &finaly);


caminho(iniciox, inicioy, &finalx, &finaly);

return 0;
}
Exercício 1
● Escreva uma função recursiva que determine se uma palavra é palíndroma ou
não.
○ Qual o caso base?

○ Qual o passo indutivo (processamento)?


Exercício 2
● Crie um programa em C, que contenha uma função recursiva para encontrar o
menor elemento em um vetor.

● A leitura dos elementos do vetor e impressão do menor elemento devem ser


feitas no programa principal

● Caso base?

● Passo indutivo?
Exercício 3
● Escreva uma função recursiva que dado um número n, gere todas as possíveis
combinações com as n primeiras letras do alfabeto.
○ Ex.: n = 3. Resposta: ABC, ACB, BAC, BCA, CAB, CBA
Exercício 4
● Escreva uma função recursiva que determine quantas vezes um dígito K ocorre
em um número natural N. Por exemplo, o dígito 2 ocorre 3 vezes em
762021192.

● Caso base?
○ Quando todos os digitos já foram examinados, ou seja, N = 0
Exercício 5

● Usando recursividade, calcule a soma de todos os valores de um array de


reais.

● Caso base?
○ Tamanho do array = 0. Soma é 0.
Exercício 6

● Dado um array de inteiros e o seu número de elementos, inverta a posição


dos seus elementos.

● Caso base?
Exercício 6

● Dado um array de inteiros e o seu número de elementos, inverta a posição


dos seus elementos.

● Caso base?
○ Tamanho do array restante é menor ou igual a 1

○ Dica! Comece pelas pontas e avance até o meio...


Respostas

https://drive.google.com/drive/folders/1dWWUKibdDIM32024GSclxyC37Sa008m
B?usp=sharing
Material Complementar

Notion:
https://www.notion.so/3-Exemplos-e117f9324ec74be4a8d97ae725907354

Textos
● Apostila de Linguagem de Programação da UFMS (Fábio Martinez)
○ https://www.facom.ufms.br/~montera/progiv1.pdf - Aula 39
● Apostila de Linguagem de Programação da USP (Silvio Lago)
○ https://www.ime.usp.br/~slago/slago-C.pdf - Seção 4.4
● Slides de aula da UFU (André Backes)
○ http://www.facom.ufu.br/~backes/gsi002/Aula09-Funcoes.pdf - páginas 23 à 28
● Geek for Geeks - Vários exemplos de problemas resolvidos com recursão (nem todas as soluções são em C, o site é
em ingles)
○ https://www.geeksforgeeks.org/practice-questions-for-recursion-set-2/?ref=lbp
Material Complementar - Videos

● Me Salva! Programação em C
○ Introdução básica com exemplo: https://youtu.be/kS_VJYWeqIQ
● C Programming & Data Structures: Recursion in C - Série com 3 vídeos (~30 min no total), com uma boa explicação e
exemplos de recursão e seus tipos ( em inglês, by indian guy :), usem a legenda auto-gerada do youtube ):
○ Video 1 - Recursão em C: https://youtu.be/kepBmgvWNDw
○ Video 2 - Tipos de Recursão P1: https://youtu.be/t9whckmAEq0
○ Video 3 - Tipos de Recursão P2: https://youtu.be/HIt_GPuD7wk
● Vídeos do Prof. André Backes sobre recursão:
○ Definição e pontos básicos P1: https://youtu.be/T2gTc5u-i1o
○ Definição e pontos básicos P2: https://youtu.be/FH5lCr-RVWE
○ Cuidados com recursão: https://youtu.be/o3MPTEc3LD8

Você também pode gostar