Você está na página 1de 5
BC0505 – Processamento da Informação Assunto: Recursividade 1. Introdução: recursividade Em um programa de

BC0505 – Processamento da Informação

Assunto: Recursividade

1. Introdução: recursividade

Em um programa de computador é muito comum chamarmos uma função dentro de uma

outra função. Entretanto, nada impede de uma função chamar ela mesma! Como exemplo, vamos

pensar na função fatorial. O fatorial de 3 e 6 respectivamente pode ser calculado conforme descrito

abaixo:

3! = 3 × 2 × 1 = 6

6! = 6 × 5 × 4 × 3 × 2 × 1 = 720

De forma genérica, podemos calcular o fatorial como:

n!=n × (n 1) × (n 2) × × 3 × 2 × 1

Deste modo, podemos facilmente implementar uma função para calcular o fatorial:

class app { static long fatorial(long n) { long fat = 1; for (long i = n; i > 1; i--) { fat *= i;

}

return fat;

}

static public void main(String s[]) {

System.out.println(fatorial(3));

System.out.println(fatorial(6));

System.out.println(fatorial(10));

}

}

Uma outra forma de entender o fatorial é:

3!=3 ×2!=3 ×2=6

6!=6 ×5!=6 ×120=720

De modo genérico, temos:

n!=n ×(n 1)!

Pela equação anterior, podemos deduzir que qualquer fatorial pode ser calculado

como o seu valor multiplicado pelo fatorial do seu valor subtraído por um. E quanto vale

o fatorial de n 1? R: (n 1)!=(n 1) × (n 2)!

Podemos propor uma função que tenta calcular a equação acima:

static long fatorial(long n) { return n * (n-1)!

}

Entretanto, como podemos calcular o (n-1)!? A função fatorial(n) que estamos

desenvolvendo não tem este objetivo? Então, por que não utilizar esta própria função para calcular o

fatorial de (n-1)? Neste sentido, teremos:

static long fatorial(long n) { return n * fatorial(n-1);

}

Entretanto, existe um erro grave nesta função: se a função chama ela mesma, quando esta

função termina e retorna? R.: Da forma que está, não termina

O principal problema do exemplo anterior é que a função não sabe quando terminar! Deste

modo, toda função recursiva precisa ter uma condição de término. Toda função recursiva deve ter

uma lógica similar ao demonstrado a seguir:

:'(

static void funcRecursiva() { // Parte Trivial if (<conhecemos_a_resposta>) return <resposta>; // Parte Geral else

return funcRecursiva();

}

No caso do fatorial, sabemos que o fatorial de 0 é 1. Esta é a nossa parte TRIVIAL. Então,

podemos alterar o código fatorial recursivo proposto da seguinte forma:

static long fatorial(long n) { // Parte Trivial if (n <= 1) return 1;

// Parte Geral else

return n * fatorial(n-1);

}

Apesar de parecer que a recursão complica a solução, conforme demonstrado no fatorial

(exemplo anterior), uma função recursiva pode facilitar a implementação de muitos problemas,

pois permite dividir o problema em problemas menores para solucioná-lo.

Para entender melhor a motivação do uso da recursão, vamos pegar um exemplo mais complexo. Lembram da Torre de Hanói? Caso não lembre, clique aqui.

da Torre de Hanói? Caso não lembre, clique aqui . Um algoritmo para solucionar a torre

Um algoritmo para solucionar a torre de Hanói não é trivial, mas podemos utilizar a recursão com o objetivo de dividir para conquistar. A chave para resolver este problema é quebrar o desafio em desafios menores até que o desafio seja trivial. Neste caso, o trivial é quando temos apenas um único disco para mover (neste caso, basta mover o disco direto). Exemplificando, se queremos mover os discos da haste 1 para a haste 3, e existem n discos na haste 1, podemos mover os n 1 discos para a haste auxiliar 2, mover o último disco da haste 1 para a haste 3 e, então, levar os n 1 discos da haste auxiliar 2 para a haste 3. Veja a figura a seguir:

para a h aste 3 e, então, levar os n − 1 discos da haste auxiliar

Ou seja, a parte TRIVIAL da nossa recursão é mover um disco da haste 1 para a haste C. A

parte GERAL (recursiva) vai ser mover os n 1 discos da haste 1 para a haste 2 e depois mover da

haste 2 para a haste 3. Um possível algoritmo seria:

void hanoi(){ // Parte TRIVIAL if (numero_de_discos == 1) <mover_o_disco_da_origem_para_o_destino>

// Parte GERAL else

hanoi(<mover_n-1_discos_da_origem_para_o_auxiliar)

<mover_o_disco_da_origem_para_o_destino>

hanoi(<mover_n-1_discos_do_auxiliar_para_o_destino)

}

Uma possível implementação em Java é apresentado a seguir.

class app { static void Hanoi(int num_discos, String hasteOrigem, String hasteDestino, String hasteAuxiliar) { // Parte TRIVIAL if (num_discos == 1) {

System.out.println("Mover o disco da haste " + hasteOrigem +

" para a haste " + hasteDestino + ".");

// Parte GERAL } else {

Hanoi(num_discos-1, hasteOrigem, hasteAuxiliar, hasteDestino); System.out.println("Mover o disco da haste " + hasteOrigem +

" para a haste " + hasteDestino + ".");

Hanoi(num_discos-1, hasteAuxiliar, hasteDestino, hasteOrigem);

}

}

static public void main(String s[]) { Hanoi(4, "A", "B", "C");

}

}

Agora tente desenvolver uma outra solução para o problema da torre de Hanói sem utilizar a

recursão. Pense um pouco e você perceberá que é muito difícil (porém não impossível).

2. Atividades em sala

Exercício 1. A sequência de Fibonacci é uma série que segue a seguinte regra: x n =x n 1 +x n 2 ,

sendo que x 1 =1 e x 2 =1. Os primeiros elementos da sequência de Fibonacci são: {1, 1, 2, 3, 5, 8, 13,

}. Um possível código

21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946,

para imprimir a sequencia de Fibonacci é apresentado abaixo:

class app { static int Fibonacci(int n) { int n1 = 1, n2 = 1; for (int i = 3; i <= n; i++) { int t = n1; n1 = n2; n2 = n1 + t;

}

return n2;

}

static public void main(String s[]) {

System.out.println(Fibonacci(3));

System.out.println(Fibonacci(6));

System.out.println(Fibonacci(9));

System.out.println(Fibonacci(12));

}

}

Faça um código que calcule a sequência de Fibonacci utilizando recursão. Exercício 2. Pode-se calcular o máximo divisor comum (MDC) entre dois números inteiros positivos utilizando o algoritmo de Euclides. Veja a implementação do algoritmo de Euclides abaixo:

class app {

static int Euclides(int a, int b) { while (b != 0) { int t = a;

}

a = b;

b = t % b;

}

return a;

static public void main(String s[]) {

System.out.println(Euclides(10,8));

System.out.println(Euclides(21,13));

System.out.println(Euclides(63,108));

}

}

Modifique o algoritmo acima de modo a utilizar recursão.

3. Atividades para casa

Exercício 01: Usando recursividade, calcule a soma de todos os valores de um vetor. Exercício 02: Usando recursividade, encontre o maior elemento de um vetor. Exercício 03: Faça uma função recursiva que inverta os elementos de um vetor. Exercício 04: Crie uma função recursiva que recebe os argumentos base e exp e calcule base exp . Considere que exp é sempre inteiro. Não é permitido utilizar o operador de potência ou laço de repetição em nenhum momento. Exercício 05: Crie uma função recursiva que verifica se um número n é primo. Exercício 06: Escreva um algoritmo recursivo capaz de gerar todas as permutações de uma String.