Programação Estruturada Prof. Rodrigo Hausen http...
Transcript of Programação Estruturada Prof. Rodrigo Hausen http...
![Page 1: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/1.jpg)
Programação Estruturada Prof. Rodrigo Hausen http://progest.compscinet.org
┌──────────┐ │ Recursão │▒ └──────────┘▒ ▒▒▒▒▒▒▒▒▒▒▒
1
![Page 2: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/2.jpg)
O QUE É?
Definição recursiva é aquela que define os elementos de um conjunto em função de outros elementos desse mesmo conjunto.
Exemplo: sequência de Fibonacci
F , F , F , … , F₀ ₁ ₂ ₙ , …
é um conjunto infinito definido por:
F := 0₀ F := 1₁ Fₙ := Fₙ + F₋₁ ₙ , se n ≥ 2₋₂
2
![Page 3: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/3.jpg)
Exemplo: sequência de Fibonacci
F := 0₀ F := 1₁ Fₙ := Fₙ − F₋₁ ₙ , se n ≥ 2₋₂
Pela definição:
F = 0₀ F = 1₁ F = F + F = 1₂ ₁ ₀ F = F + F = 2₃ ₂ ₁ F = F + F = 3₄ ₃ ₂ F = F + F = 5₅ ₄ ₃ F = F + F = 8₆ ₅ ₄
Calcule F .₉3
![Page 4: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/4.jpg)
FUNÇÕES RECURSIVAS
Função recursiva é aquela definida usando-se a própria função.
Exemplo: considere a função
f : → ℕ ℕ ⎧ 0, se n é 0 n ↦ f(n) := 1, se ⎨ n é 1 ⎩ f(n−1) + f(n−2), se n ≥ 2
Observe que, pela forma como definimos a função, f(n) equivale a F .ₙ
4
![Page 5: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/5.jpg)
FUNÇÕES RECURSIVAS em C
Podemos implementar funções de maneira recursiva em C.
Exemplo:
unsigned int fibonacci(unsigned int n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fibonacci(n-1) + fibonacci(n-2);
}
5
![Page 6: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/6.jpg)
FUNÇÕES RECURSIVAS em C
Podemos implementar funções de maneira recursiva em C.
Exemplo:
unsigned int fibonacci(unsigned int n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fibonacci(n-1) + fibonacci(n-2);
}
6
⎫ ⎬ casos base
⎭
↖ ↗ chamadas recursivas
![Page 7: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/7.jpg)
Outro exemplo
Fatorial de um número definido recursivamente:
0! := 1 n! := (n−1)! × n
Compare com a definição não recursiva:
⎧ 1, se n é 0 n! := ⎨ ⎩ n·(n−1)·(n−1)·…·2·1, se n ≥ 1
Implemente a função fatorial de maneira recursiva e não recursiva em C.
7
![Page 8: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/8.jpg)
// implementação recursivaunsigned int fatorial(unsigned int n) { if (n == 0) return 1; return n*fatorial(n-1);}_______________________________________
// implementação não recursivaunsigned int fatorial(unsigned int n) { unsigned int produto = 1; unsigned int i; for(i = n; i >= 1; --i) { produto *= i; } return produto;} 8
![Page 9: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/9.jpg)
// implementação recursivaunsigned int fatorial(unsigned int n) { if (n == 0) return 1; ← caso base
return n*fatorial(n-1);}_______________________________________
// implementação não recursivaunsigned int fatorial(unsigned int n) { unsigned int produto = 1; unsigned int i; for(i = n; i >= 1; --i) { produto *= i; } return produto;} 9
↖ chamada recursiva
![Page 10: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/10.jpg)
LEMBRE-SE
Em C, toda função recursiva sempre deve ter:
→ pelo menos 1 chamada recursiva (óbvio, senão não seria uma função recursiva)
→ pelo menos 1 caso base (caso contrá- rio a recursão não terá fim, ou seja, a execução nunca termina)
Verifique sempre se os casos base são atingidos para quaisquer valores de entrada e se todos os casos base foram considerados.
10
![Page 11: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/11.jpg)
FALTA DE CASO BASE: consequências
Nesta função recursiva, o programador esqueceu de considerar o caso base:
unsigned int fatorial(unsigned int n) { if (n == 0) return 1; return n*fatorial(n-1);}
[cling]$ .L fatorial.c[cling]$ fatorial(2)▉
11
![Page 12: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/12.jpg)
FALTA DE CASO BASE: consequências
Nesta função recursiva, o programador esqueceu de considerar o caso base:
unsigned int fatorial(unsigned int n) { if (n == 0) return 1; return n*fatorial(n-1);}
[cling]$ .L fatorial.c[cling]$ fatorial(2)Falha de segmentação
12
![Page 13: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/13.jpg)
FALTA DE CASO BASE: consequências
#include <stdio.h>unsigned int fatorial(unsigned int n) { printf("fatorial(%u)\n", n); if (n == 0) return 1; return n*fatorial(n-1);}
[cling]$ fatorial(2)▉
13
![Page 14: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/14.jpg)
FALTA DE CASO BASE: consequências
#include <stdio.h>unsigned int fatorial(unsigned int n) { printf("fatorial(%u)\n", n); if (n == 0) return 1; return n*fatorial(n-1);}
[cling]$ fatorial(2)fatorial(2)fatorial(1)fatorial(0)fatorial(4294967295)fatorial(4294967294)…Falha de segmentação
14
![Page 15: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/15.jpg)
FALTA DE CASO BASE: consequências
#include <stdio.h>unsigned int fatorial(unsigned int n) { printf("fatorial(%u)\n", n); if (n == 0) return 1; return n*fatorial(n-1);}
[cling]$ fatorial(2)fatorial(2)fatorial(1)fatorial(0)fatorial(4294967295)fatorial(4294967294)…Falha de segmentação
15
underflow da variável n
⎫ falta de caso base faz com que ⎬ não exista critério de parada. ⎭ função executa indefinidamente
![Page 16: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/16.jpg)
FALTA DE CASO BASE: consequências
Cada chamada a uma função ocupa espaço na região de memória chamada pilha.
Quando a função termina de ser executa-da, o espaço alocado à função é liberado
Em função recursiva, se o caso base nunca é atingido, a função chama a si própria mas nunca termina!
Cada chamada ocupa mais espaço na pilha.
Uma hora, o espaço na pilha acaba, resultando em falha de segmentação.
16
![Page 17: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/17.jpg)
ESTOURO DE PILHA
Quando acaba a memória disponível para a pilha, temos uma condição chamada estouro de pilha ou transbordamento de pilha (stack overflow).
Um dos motivos para o esturo de pilha é a execução de função recursiva que não atinge nenhum caso base.
Porém, mesmo funções recursivas com casos base bem definidos podem estourar a pilha caso o número de chamadas recursivas cresça muito rapidamente.
17
![Page 18: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/18.jpg)
GRAFO DE CHAMADAS de fibonacci(4)
18
fibonacci(4)
fibonacci(3) fibonacci(2)
fibonacci(2) fibonacci(1) fibonacci(1) fibonacci(0)
fibonacci(1) fibonacci(0)Seja T(n) o número dechamadas recursivas em fibonacci(n). Estime-o.
![Page 19: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/19.jpg)
GRAFO DE CHAMADAS de fibonacci(4)
T(0) = 0, T(1) = 1,T(n) = 2 + T(n−1) + T(n−2), n ≥ 2
19
fibonacci(4)
fibonacci(3) fibonacci(2)
fibonacci(2) fibonacci(1) fibonacci(1) fibonacci(0)
fibonacci(1) fibonacci(0)Seja T(n) o número dechamadas recursivas em fibonacci(n). Estime-o.
![Page 20: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/20.jpg)
0 1 2 3 4 5 6 7 8 9 10 11 120
50
100
150
200
250
300
350
400
450
500
CHAMADAS RECURSIVAS em fibonacci(n)
T(n) > Fₙ para n ≥ 2
20
T(n)
Fₙ
![Page 21: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/21.jpg)
QUANDO NÃO SE DEVE USAR RECURSÃO?
→ Quando o número de chamadas recursivas cresce muito rapidamente (risco de estouro de pilha para entradas muito pequenas)
→ Quando há soluções iterativas simples
unsigned int fatorial(unsigned int n) { if (n == 0) return 1; return n*fatorial(n-1);}
21
![Page 22: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/22.jpg)
QUANDO NÃO SE DEVE USAR RECURSÃO?
→ Quando o número de chamadas recursivas cresce muito rapidamente (risco de estouro de pilha para entradas muito pequenas)
→ Quando há soluções iterativas simples
unsigned int fatorial(unsigned int n) { int i, produto = 1; for (i=n; i>=1; --i) { produto *= n; } return produto;}
22
![Page 23: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/23.jpg)
QUANDO NÃO SE DEVE USAR RECURSÃO?
Transforme a implementação de fibonacci em uma solução iterativa.
unsigned int fibonacci(unsigned int n) {
if (n == 0) return 0;
if (n == 1) return 1;
return fibonacci(n-1) + fibonacci(n-2);
}
23
![Page 24: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/24.jpg)
QUANDO NÃO SE DEVE USAR RECURSÃO?
unsigned int fibonacci(unsigned int n) { if (n == 0) return 0; if (n == 1) return 1; int i, fn; int fnmenos1 = 1, fnmenos2 = 0; for (i = 2; i<= n; ++i) { fn = fnmenos1 + fnmenos2; fnmenos2 = fnmenos1; fnmenos1 = fn; } return fn;}
24
![Page 25: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/25.jpg)
QUANDO É VANTAJOSO USAR RECURSÃO?
→ Quando o número de chamadas cresce muito devagar
→ Quando o problema é definido de maneira recursiva e implementação é viável (p.ex. para algumas estrutu- ras de dados, tipo árvores binárias)
Às vezes, uma solução recursiva pode ser ponto de partida para uma solução iterativa.
25
![Page 26: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/26.jpg)
ESTUDOS DE CASO
→ Máximo Divisor Comum
→ Busca binária
26
![Page 27: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/27.jpg)
MÁXIMO DIVISOR COMUM
Máximo Divisor Comum (MDC) entre dois números naturais a e b, tais que a ≠ 0:
→ maior inteiro M tal que M é divisor de a e de b.
Exemplo: o MDC entre 84 e 72 é 12, pois 12 é o maior inteiro que divide ambos.
Veja que:→ mdc(a, 0) = a→ Se b ≠ 0, mdc(a, b) = mdc(b, a mod b)
Onde a mod b é o resto da divisão de a por b.
27
![Page 28: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/28.jpg)
MÁXIMO DIVISOR COMUM
// cálculo do máximo divisor comum para// números naturais a, b tais que a ≠ 0unsigned int mdc(unsigned int a, unsigned int b) { if (b == 0) return a; return mdc(b, a % b);}
28
![Page 29: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/29.jpg)
MÁXIMO DIVISOR COMUM
// cálculo do máximo divisor comum para// números naturais a, b tais que a ≠ 0unsigned int mdc(unsigned int a, unsigned int b) { if (b == 0) return a; return mdc(b, a % b);}
[cling]$ mdc(84, 72)(unsigned int) 12
29
![Page 30: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/30.jpg)
MÁXIMO DIVISOR COMUM
// cálculo do máximo divisor comum para// números naturais a, b tais que a ≠ 0unsigned int mdc(unsigned int a, unsigned int b) { if (b == 0) return a; return mdc(b, a % b);}
[cling]$ mdc(84, 72)(unsigned int) 12[cling]$ mdc(144, 90)(unsigned int) 18
30
![Page 31: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/31.jpg)
MÁXIMO DIVISOR COMUM
// cálculo do máximo divisor comum para// números naturais a, b tais que a ≠ 0unsigned int mdc(unsigned int a, unsigned int b) { if (b == 0) return a; return mdc(b, a % b);}
[cling]$ mdc(84, 72)(unsigned int) 12[cling]$ mdc(144, 90)(unsigned int) 18[cling]$ mdc(13, 5)(unsigned int) 1
31
![Page 32: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/32.jpg)
MÁXIMO DIVISOR COMUM
// cálculo do máximo divisor comum para// números naturais a, b tais que a ≠ 0unsigned int mdc(unsigned int a, unsigned int b) { if (b == 0) return a; return mdc(b, a % b);}
[cling]$ mdc(144, 90)(unsigned int) 18[cling]$ mdc(13, 5)(unsigned int) 1[cling]$ mdc(21, 0)(unsigned int) 21
32
![Page 33: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/33.jpg)
MÁXIMO DIVISOR COMUM
// cálculo do máximo divisor comum para// números naturais a, b tais que a ≠ 0unsigned int mdc(unsigned int a, unsigned int b) { if (b == 0) return a; return mdc(b, a % b);}
[cling]$ mdc(13, 5)(unsigned int) 1[cling]$ mdc(21, 0)(unsigned int) 21[cling]$ mdc(0, 0)(unsigned int) 0 ← o resultado deveria ser “indetermina- do” pois 0 não divide 0. Mas não temos como representar isso...
33
![Page 34: Programação Estruturada Prof. Rodrigo Hausen http ...compscinet.org/hausen/courses/2016/q3/progest/... · rio a recursão não terá fim, ou seja, a execução nunca termina) Verifique](https://reader033.fdocuments.net/reader033/viewer/2022043008/5f9910cec10fd9730b28c889/html5/thumbnails/34.jpg)
MÁXIMO DIVISOR COMUM
Para casa:
→ implemente a função mdc de maneira iterativa
→ como você alteraria na função mdc para que ela funcionasse para inteiros quaisquer (com sinal)
34