Вы находитесь на странице: 1из 14

Captulo 3.

2
Algoritmos Iterativos vs. Recursivos

Algoritmos e Estruturas de Dados

2007-2008 , Gladys Castillo

Algoritmos Iterativos
Um algoritmo iterativo usa estruturas de repetio (ciclos) para resolver problemas
Exemplo: A funo factorial static int factorial (int n) { static factorial int fact = 1; int for (int i=2; i<=n, i++) for int int fact = fact * i; return fact; return }

Um ciclo usado para calcular o factorial de um nmero

Algoritmos e Estruturas de Dados,

2007-2008 , Gladys Castillo

Algoritmos Recursivos
Um algoritmo recursivo possui a caracterstica de invocar-se a sim prprio repetidamente at que certa condio seja satisfeita
Exemplo: A funo factorial

static int factorial (int n) { static factorial if (n == 0) if return 1; return else else factorial(n-1); return n * factorial return factorial }
Algoritmos e Estruturas de Dados,

Uma funo recorrente inclui uma instruo de deciso que decide se parar o continuar a recorrncia.

2007-2008 , Gladys Castillo

rvore de Recorrncia
Clculo de 4!
4! = 4 x 3! = 4 x 6 = 24
3!=6

4!

4! = 4 x 3!

3!
2!=2

3! = 3 x 2!

2!
1!=1

2! = 2 x 1!

1!
Desenhos extrados de http://www.lcc.uma.es/~lopez/modular/recursion/ transp_recursion.pdf Autor: Pablo Lpes 0!=1

1! = 1 x 0!

0!
2007-2008 , Gladys Castillo
4

Algoritmos e Estruturas de Dados,

Caixa de Execuo
Clculo de 4!
4! = 24
O valor de 4! calculado no regresso das sucessivas invocaes da funo recursiva, pelo que 4! = 1 x 1 x 2 x 3 x 4 = 24 factorial(4) = 4 x factorial(3) =4x6 factorial(3) = 3 x factorial(2) =3x2 factorial(2) = 2 x factorial(1) =2x1 factorial(1) = 1 x factorial(0) =1x1 factorial(0) = 1

Cada caixa representa o espao de execuo de uma nova chamada da funo. Em total so efectuadas 5 chamadas e 4 multiplicaes

Memria utilizada: 4 bytes x 5 Cada chamada gera uma cpia do valor do parmetro n pelo que no eficiente em termos da utilizao da memria
Algoritmos e Estruturas de Dados, 2007-2008 , Gladys Castillo

Desenho de Algoritmos Recursivos


Ideia bsica: diminuir sucessivamente o problema em um problema menor, at que o tamanho do problema reduzido permita resolve-lo de forma directa, sem recorrer a si mesmo. Neste caso, diz-se que o algoritmo atingiu o critrio de paragem.

Devemos considerar as seguintes questes:


Definir o caso base:
Qual o caso base do problema que pode ser resolvido sem quaisquer chamadas recursivas?

Definir formula recursiva:


Como definir o problema em termos do mesmo problema de menor dimenso? A diminuio da dimenso do problema em cada chamada recursiva garante que seja sempre atingido o caso base e por consequncia o critrio de paragem?
Algoritmos e Estruturas de Dados, 2007-2008 , Gladys Castillo
6

Sucesso de Fibonacci
Esta sucesso foi estudada pelo matemtico Leonardo Fibonacci (1170-1250), quando conjecturava acerca do crescimento de uma populao de coelhos.

F(n) =

F(1)= F(2) =1 F(n-1) + F(n-2), se n> 2

N de pares 1, 1, 2, 3, 5, 8, 13, 21, 34,

Algoritmos e Estruturas de Dados,

2007-2008 , Gladys Castillo

Sucesso de Fibonacci Algoritmo Iterativo vs. Recursivo


verso iterativa verso recursiva

static int fibonacci (int n) { static fibonacci int f, f1, f2; int if (n<=2) return 1; return if f1 = 1; f2 = 1; for (int i=3; i<=n, i++){ for int int f = f1 + f2; f1 = f2; f2 = f; } return f; return }

static int fibonacci (int n) { static fibonacci if (n <= 2) if return 1; return else else return fibonacci (n-1) + fibonacci (n-2) ; return }

O algoritmo recursivo mais elegante e parecido com a definio da sucesso, mas muito menos eficiente do que a sua verso iterativa

Algoritmos e Estruturas de Dados,

2007-2008 , Gladys Castillo

rvore de Recorrncia
Clculo do Fibonacci de 6
A soluo recursiva ineficiente pois para calcular o Fibonacci de 6, calcula repetidamente valores intermdios:
2 vezes F(4), 3 vezes F(3), 5 vezes F(2) e 3 vezes o F(1) F(6) = 8

hhhhh
Algoritmos e Estruturas de Dados, 2007-2008 , Gladys Castillo
9

Coeficiente Binomial e Tringulo de Pascal


O tringulo de Pascal um tringulo numrico infinito formado pelos coeficientes dos binmios de Newton (a+b)n

Tringulo de Pascal

C ( n, k ) =

n! ( n k )!k!

onde n representa o n da linha e k o n da coluna


para obtermos os coeficientes do desenvolvimento do binmio (a+b)2, basta olharmos a 3 linha do tringulo para escrevermos: (a+b)2 = 1 a2 + 2ab + 1b2

Cada elemento, com excepo dos elementos terminais da cada linha calculado atravs da soma dos valores da linha anterior, ou seja: C(n,0) = C(n, n) = 1 C(n, k) = C(n-1, k-1) + C (n-1, k) ,
Algoritmos e Estruturas de Dados,

se 0<k<n
10

2007-2008 , Gladys Castillo

Clculo do Coeficiente Binomial


Algoritmo Recursivo
static int coefBinomial (int n, int k) { static coefBinomial if (k > n) return 0; if return if (k = 0 || k = 1) return 1; if return return coefBinomial (n-1, k-1) + return coefBinomial (n-1, k) ; }
Esta implementao computacionalmente ineficiente para valores elevados de k e n. Devido dupla invocao recursiva a rvore de recorrncia cresce rapidamente, repetindo o clculo de certos valores (o mesmo que acontecia com os nmeros Fibonacci).

Trabalho para casa: 1. Imprimir o tringulo de Pascal usando o algoritmo recursivo 2. Implementar a verso iterativa para o clculo do coeficiente binomial

Algoritmos e Estruturas de Dados,

2007-2008 , Gladys Castillo

11

Invertir Nmero Algoritmo Iterativo vs. Recursivo


verso iterativa verso recursiva

static void inverterNumero static void inverterNumero(int n){ inverterNumero while (n >0){ while System.out.print(n%10); n /=10; } }

static void inverterNumero static void inverterNumero(int n){ inverterNumero System.out.print(n%10); if (n / 10 > 0) if inverterNumero(n inverterNumero /10); inverterNumero } }
O algoritmo recursivo mais elegante e mais fcil

Trabalho para casa: Escrever a rvore de recorrncia para a verso recursiva

Algoritmos e Estruturas de Dados,

2007-2008 , Gladys Castillo

12

Tipos de Recursividade
Existem trs tipos de algoritmos recursivos:
1. Recursividade directa:

a funo tem uma chamada explicita a si prpria


2. Recursividade indirecta:

a funo F chama a funo G que por sua vez chama a funo F


3. Recursividade tail:

o valor de retorno o valor de retorno da chamada recursiva (no existem operaes pendentes)

Algoritmos e Estruturas de Dados,

2007-2008 , Gladys Castillo

13

Torres de Hanoi
Edouard Lucas, 1883
Deslocar todos os discos da Torre A para a Torre C, um de cada vez Utilizar a Torre B como auxiliar Nunca colocar nenhum disco, sobre outro menor

Incio

Torre A

Torre B

Torre C

Fim

Torre A

Torre B

Torre C
14

Algoritmos e Estruturas de Dados,

2007-2008 , Gladys Castillo

Torres de Hanoi
Algoritmo Recursivo
Mover n discos de A para C usando B como auxiliar
mover n-1 discos de A para B usando C como auxiliar mover 1 disco de A para C mover n-1 discos de B para C usando A como auxiliar
recurso
mover n -1 discos de A para B usando C como auxiliar
A B C

mover 1 disco de A para C

mover n discos de A para C usando B como auxililar

recurso
mover n-1 discos de B para C usando A como auxililar
A B C
15

Algoritmos e Estruturas de Dados,

2007-2008 , Gladys Castillo

Torres de Hanoi
Algoritmo Recursivo em Java
static void torresHanoi (int n, int origem, int auxiliar, int destino) { if (n == 1){ moverDisco (origem, destino); } else { torresHanoi (n-1, origem, destino, auxiliar); moverDisco (origem, destino); torresHanoi (n-1, auxiliar, origem, destino); } } static void moverDisco (int origem, int destino){ System.out.println (desde : + origem + -}

para: + destino);

O nmero de movimentos simples necessrios para mover n discos 2n-1


Algoritmos e Estruturas de Dados, 2007-2008 , Gladys Castillo
16

Ordenao por Separao


O algoritmo Quicksort
Algoritmo recursivo:
escolher um elemento p como piv da sequncia e dividi-la em duas partes:
na parte esquerda: colocam-se os valores menores do que o piv p na parte direita: colocam-se os valores maiores do que o piv p Logo aplicado este mesmo procedimento de forma recursiva com a parte esquerda e direita da sequncia. O algoritmo termina ao se atingir uma sequncia de um elemento a sequncia est ordenada
numero[i]<p dividir numero[i]>p

ini

fim

aplicar Quicksort medio

aplicar Quicksort

Escolha do piv:
O 1 elemento da sequncia O elemento do mdio e depois colocar o piv por forma a que ini, medio e fim fiquem por ordem crescente
2007-2008 , Gladys Castillo
17

Algoritmos e Estruturas de Dados,

O Algoritmo Quicksort
static void quickSort (int [ ] seq, int ini, int fim) { int if (seq.length == 1 || ini > fim) return; if (seq.length == 2) { /* sequncia com 2 elementos */ trocar(seq, ini, fim); if (seq[ini] > seq[fim]) trocar return; return; } /* calcular o ndice do piv no meio */ int medio = (ini + fim) /2; /* colocar o piv por forma a que ini, medio e fim fiquem por ordem crescente */ colocarPivo (seq, ini, medio, fim); return; if (seq.length == 3) return // se sequncia com 3 elementos ento j est ordenada /* dividir a sequencia: na parte esquerda colocam-se os valores menores do que o piv na parte direita, os valores maiores do que o piv */ medio = dividirSeq (seq, ini, medio, fim); quickSort (seq, ini, medio-1); // invocao recursiva para a parte esquerda da sequncia quickSort (seq, medio+1, fim); // invocao recursiva para a parte direita da sequncia
Algoritmos e Estruturas de Dados, 2007-2008 , Gladys Castillo
18

O Algoritmo Quicksort
Mtodos: trocar e colocarPivot
private static void trocar (int[ ] seq, int ind1, int ind2){ int temp = seq[ind1]; seq[ind1] = seq[ind2]; seq[ind2] = seq[temp]; } private static void colocarPivo (int[ ] seq, int ini, int medio, int fim){ /* colocar o piv por forma a que ini, medio e fim fiquem por ordem crescente */ trocar(seq, ini, medio); if (seq[ini] > seq[medio]) trocar trocar(seq, ini, fim); if (seq[ini] > seq[fim]) trocar trocar(seq, medio, fim); if (seq[medio] > seq[fim]) trocar }

Algoritmos e Estruturas de Dados,

2007-2008 , Gladys Castillo

19

O Algoritmo Quicksort
Mtodo: dividirSeq (I)
private static int dividirSeq ( int[ ] seq, int ini, int medio, int fim ){ int indEsq = ini + 1; int indDir = fim - 1; while (indEsq < indDir) { // 1. procurar elementos na parte esquerda maiores do que piv while (indEsq < medio){ break; if (seq[indEsq] > seq[medio]) break indEsq++; } // 2. procurar elementos na parte direita menores do que piv while (indDir > medio){ break; if (seq[indDir] < seq[medio]) break indDir--; }
Algoritmos e Estruturas de Dados, 2007-2008 , Gladys Castillo
20

10

O Algoritmo Quicksort
Mtodo: dividirSeq (II)
// 3. trocar elementos segundo 3 casos Caso I: existe um elemento na if (indEsq != medio && indDir != medio){ parte esquerda maior do que piv e um elemento na parte direita trocar (seq, indEsq, indDir); menor do que piv ento trocar os indEsq++; indDir--; elementos } else if (indEsq == medio && indDir != medio){ trocar (seq, medio,indDir); Caso II: existe um elemento na parte direita menor do que piv, medio++; ento trocar o elemento de ndice trocar(seq, medio,indDir); if (medio != indDir) trocar indDir com o piv e deslocar o indEsq = medio; // a parte esquerda j est OK piv uma posio direita } else if (indEsq != medio && indDir == medio){ trocar(seq, medio,indEsq); trocar Caso III: existe um elemento na medio --; parte esquerda maior do que piv, if (medio != indEsq) trocar (seq, medio, indEsq); ento trocar o elemento de ndice indEsq com o piv e deslocar o indDir= medio; }// a parte direita j est Ok piv uma posio esquerda } // fecho while return medio;
Algoritmos e Estruturas de Dados, 2007-2008 , Gladys Castillo
21

Exemplo do Algoritmo Quicksort


(VER Programao

avanada usando C, Antnio Rocha, pag 189)


fim = 9 55 145 indEsq = 2 42 55 25 15 145 2 indDir = 7 32 8 330 209

ini = 0 209 330 25 15 42

medio = 4 2 32 8

Trocar 145 com 8 Como 209, 42 e 145 no esto ordenados Trocar 209 com 42 e 209 com 145

medio ++ 8 2 32 145 330 209

42 55 25 fim = 9 8 55 209

15

ini = 0 42 330 25 15

medio = 4 145 2 32

Trocar 2 com 145

medio = 5 8 145 32 2 330 209

42 55 25

15

piv 145: na parte esquerda colocam-se os valores menores do que o piv e na parte direita, os valores maiores do que o piv

indEsq = 5 42 55 25 indEsq = 6 15 8

indDir = 7 2 330 209

145 32

executar dividirSeq(seq, 0, 4, 9) indEsq = 1 42 330 25 15 145 2 32

indDir = 8 8 55 209

Trocar 145 com 8, medio ++, trocar 32 com 145

medio = 6 15 8 2

indDir = 7 145 32 330 209

42 55 25

Trocar 330 com 55

Trocar 145 com 332

medio = 7 8 2 32 145 330 209


quickSort(seq, 8, 9)

42 55 25 42 55 25 15 145 2 32 8 330 209

15

Chamar quickSort (seq, 0, 6)


2007-2008 , Gladys Castillo
22

Algoritmos e Estruturas de Dados,

11

Ordenao Quicksort
Complexidade
Este algoritmo considerado uns dos melhores algoritmos de ordenao, pois apesar de, no pior caso, ser um algoritmo quadrtico, no caso mdio tem uma complexidade linear logartmica de comparaes, ou seja de ordem O(n log2 n)
n de comparaes

pior caso: ordem quadrtico caso meio: ordem linear logartmica

WC(n) n2 AC(n) 1.4 n . log2 (n)

Outro algoritmo recursivo de ordenao de complexidade linear logartmica tambm muito popular o algoritmo MergeSort (ordenao por fuso). Pode ler sobre este algoritmo no livro Programao avanada usando C de Antonio Rocha, pag 184

Algoritmos e Estruturas de Dados,

2007-2008 , Gladys Castillo

23

Recursividade vs. Iterao


Todo problema que se resolve recursivamente pode ser resolvido iterativamente
Mas como regra geral:
os algoritmos recursivos so mais simples e elegantes
possuem cdigo mais claro (legvel) e mais compacto do que os correspondentes iterativos se os problemas so de natureza recursivas so mais fceis de serem implementados em linguagens de programao de alto nvel

os algoritmos recursivos so menos eficientes


consomem mais recursos devido invocao sucessiva da funo recursiva: gasta-se mais tempo na execuo do algoritmo e muito mais memria. Porm pode valer a pena sacrificar a eficincia em beneficio da clareza

os algoritmos recursivos so mais difceis de ser depurados


Especialmente quando for alta a profundidade da recurso, ou seja, o nmero mximo de chamadas simultneas
Algoritmos e Estruturas de Dados, 2007-2008 , Gladys Castillo
24

12

Recursividade vs. Iterao


Concluso
Quando devemos usar algoritmos recursivos?
Usar se: Os problemas so de natureza recursiva. Neste caso, a soluo recursiva a mais natural, elegante e fcil de implementar A soluo recursiva no leva a uma excessiva repetio do clculo dos mesmos valores A soluo iterativa equivalente muito complexa (ex: problema das Torres de Hanoi)

Algoritmos e Estruturas de Dados,

2007-2008 , Gladys Castillo

25

Bibliografia
C. Thomas Wu: An introduction to Object-Oriented Programming with Java, third edition. Chapter 15: Recursive Algorithms
slides online:
http://highered.mcgraw-hill.com/sites/0072518847/student_view0/chapter15/powerpoint.html

Roslia Rodrigues: Introduo Anlise e Desenvolvimento de Algoritmos. Captulo 3. Recorrncia


on-line em: http://www2.mat.ua.pt/rosalia/cadeiras/ADA/Cap3Recorrencia.pdf

Antnio Adrego da Rocha: Programao Avanada usando C. Tecnologias da Informao. FCA Editora de Informtica, 2006 Captulo 1. Recursividade, Captulo 6.6. Algoritmos de ordenao recursivos
Nota: Algumas das figuras usadas nos acetatos foram extradas destas fontes
Algoritmos e Estruturas de Dados, 2007-2008 , Gladys Castillo
26

13

Caixa de Execuo
Clculo de 4!
true
O valor de palindromo(somos) calculado no regresso das sucessivas invocaes da funo recursiva, pelo que palindromo(somos) = (s == s) && (o == o) && true = true palindromo(somos) = (s == s) && palindromo(omo) = true && palindromo(omo) = (o == o) && palindromo(m) = true && true true

palindromo(m) = true

Algoritmos e Estruturas de Dados,

2007-2008 , Gladys Castillo

27

14

Вам также может понравиться