Recursividade
Conceitos e Aplicações
Recursividade
•
Um algoritmo é dito recursivo quando ele chama a si
mesmo ou chama uma seqüência de outros
algoritmos, e um deles chama novamente o primeiro
algoritmo. Suas características são:
•
•
•
•
Divisão do problema original em pequenas
ocorrências
Abordagem “dividir para conquistar” (divide and
conquer)
Dificuldade no reconhecimento das aplicações e
também no equilíbrio entre espaço (memória
ocupada) e tempo (tempo de execução)
Fornece uma boa compreensão da solução do
problema
Recursividade – Função Fatorial
Definição da função:
n! = 1,
se n = 0
n! = n * (n – 1)!
se n > 0
Calculando 4! usando a última definição, faríamos:
4! = 4 x3!
= 4 x (3 x 2!)
= 4 x (3 x (2 x 1!))
= 4 x (3 x (2 x (1 x 0!))).
= 4 x (3 x (2 x (1 x 1)))
= 4 x (3 x (2 x 1))
= 4 x (3 x 2)
=4x6
= 24
Recursividade – Funções Recursivas
Possuem, sempre, duas partes:
•
•
Solução trivial : dada por definição, obtida sem
recursão
Solução geral : parte do problema que em essência é
igual ao problema original, sendo, porém, menor
Seu controle é feito através de pilhas:
•
•
•
Chamadas e retornos de rotinas: utilizam a pilha
Quando uma rotina é chamada, empilha-se: o
endereço de retorno + todas as variáveis locais
Quando ocorre o retorno da rotina, as variáveis locais
que foram criadas deixam de existir
Recursividade – Função Fatorial
•
Versão recursiva da função fatorial
public int Fatorial(int n)
{
if (n==0) return 1;
else return n*Fatorial(n-1);
}
•
Vamos realizar uma simulação da execução da
função fatorial com o valor 4.
Recursividade – Função Fatorial
•
Outra função recursiva: máximo divisor comum
public int MDC(int p1, int p2)
{
if (p2==0)
MDC = p1;
else
return MDC(p2, p1 % p2);
}
Recursividade – Algoritmos Recursivos
•
•
•
•
•
•
•
Pode ser conciso e elegante
Pode ser difícil a compreensão dos detalhes de seu
funcionamento computacional
Pode requerer um exaustivo acompanhamento do
programa
O computador pode utilizar pilhas para esse controle
A mente humana não é tão boa para tais tarefas
Parece ser difícil para uma pessoa guardar uma longa
seqüência de resultados e então voltar para terminar
um trabalho
Para acompanhar tais algoritmos, podemos utilizar,
por exemplo, árvores de recursão
Recursividade – Torres de Hanói
Na criação do mundo, aos sacerdotes do Templo de Brahma
(montanhas de Hanoi – sacerdotes brâmanes), foi dada uma
plataforma de metal na qual existiam três hastes de diamante.
Na primeira haste existiam 64 discos de ouro, cada um
ligeiramente menor em relação ao que estava por baixo.
Os sacerdotes foram incumbidos com a tarefa de mover todos os
discos de ouro da primeira haste para a terceira, porém, com as
seguintes condições :
- Mover apenas um disco por vez;
- Nenhum disco poderia ficar sobre um disco maior.
Aos sacerdotes foi dito que quando eles terminassem de
movimentar os 64 discos de ouro, o mundo terminaria!!!
Recursividade – Torres de Hanói
1
•
3
Como poderíamos ajudar os sacerdotes?
-
•
2
Criando um programa que liste a ordem de operações que eles
devem realizar...
Pode-se resumir a tarefa na seguinte instrução:
Move (64,1,3,2)
•
Que significa: “Mova 64 discos da torre 1 para a torre
3, usando a torre 2 como armazenamento temporário”
Recursividade – Torres de Hanói
•
•
•
•
•
•
Concentrar nossa atenção não no primeiro passo
Mas sim, no passo mais difícil: mover o último disco.
Como acessar o disco número 64?
Lembre-se que somente um disco pode ser movido
por vez
E o último (o maior) não pode nunca estar sobre os
demais
Quando movemos o disco 1, não pode existir nenhum
outro disco nas torres 1 e 3
Recursividade – Torres de Hanói
•
A primeira chamada da função, para mover os 64
discos é:
Move (64, 1, 3, 2)
•
E a função Move, recursiva, pode ser descrita como:
public void Move (int count, int start, int
finish, int temp)
{
if (count > 0) {
Move (count–1, start, temp, finish);
/* Escrever na tela que o usuário deve
mover o disco
do topo da haste <start>
para a <finish>*/
Move (count-1, temp, finish, start);
}
}
Recursividade – Torres de Hanói
•
Observando a árvore de recursão, podemos concluir
o seguinte:
- Nr de movimentos para movimentar todos 64
discos é de: 264 –1
- Para tentar aproximar o valor, consideremos 210 
103
- Número de passos de aproximadamente 1,6 * 1019
- Existem aproximadamente 3,2 * 107 segundos num
ano
- Vamos supor que as instruções sejam executadas
num ritmo de um movimento por segundo
- A tarefa total levará quase 5 x 1011 anos
- Estimativa de vida do universo: mínimo 20 bilhões
(2 * 1010) anos
Recursividade – Torres de Hanói
•
Não existe um computador que rode o programa de
Torres de Hanói para 64 discos
•
Ele falharia por falta de tempo
•
Mas certamente não por falta de espaço
•
O espaço necessário é somente para fazer o controle
de 64 chamadas recursivas
•
Mas o tempo necessário requerido, é aquele para
fazer 264 cálculos
Recursividade – Criando Algoritmos
a) Ache o passo chave:
- “Como este problema pode ser dividido ? “
- “Como posso desenvolver o passo chave da solução ?”
b) Ache uma regra de parada:
- Uma regra de parada indica que o problema ou uma
parte razoável do mesmo foi feito
- Ela é geralmente pequena e dá a solução trivial, sem a
necessidade da recursão
c) Monte seu algoritmo:
- Combine a regra de parada e o “passo chave” usando
uma instrução IF
Recursividade – Criando Algoritmos
d) Verifique o término:
- Certificar que a recursão sempre terminará
- Comece com uma situação geral
- Verifique se num número finito de passos, a regra de
parada será satisfeita e a recursão termina
e) Desenhe uma árvore de recursão:
- É a ferramenta chave para analisar algoritmos
recursivos
Recursividade – Recursão de Cauda
•
Essa situação na qual a chamada recursiva é o último
comando da função, é denominada recursão de cauda
•
Isso forma um “looping” que será repetido até que
uma condição de parada seja satisfeita
•
A recursão de cauda pode sofrer transformações até
ser obtido uma estrutura de iteração, quando
observaremos ganhos em tempo e espaço
Recursividade – Recursão de Cauda
// Fatorial recursiva
public int Fatorial(int n)
{
if (n==0)return 1;
else return n*fatorial(n-1);
}
// Fatorial iterativa
public int Fatorial (int n)
{
int count, product = 1;
for (count = 1; count < = n; count ++)
product*= count;
return product;
}
Recursividade – Conclusão
•
A recursão é considerada uma abordagem top-down
para resolver um problema
•
A interação está mais para um abordagem bottom-up
•
É sempre verdadeiro que a recursão pode ser
substituída pela interação e pilhas
•
É verdade também, por outro lado, que qualquer
programa interativo que manipula uma pilha pode ser
substituído por um programa recursivo sem nenhuma
pilha
Fim
Download

Recursividade - caversan.eng.br