Buscar

PAA+ +2019 01+ +parte+03

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 50 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 50 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 50 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

Projeto e Análise de Algoritmos
3ª parte
Prof. Jobson Massollar
jobson.silva@uva.br
Projeto e Análise de Algoritmos2
Estruturas de Controle
➢ Conforme visto anteriormente, para calcular a função f(n) de tempo
de um algoritmo devemos contar o números de passos elementares
do mesmo:
int soma(int n) {
int i;
int acumulador = 0;
for(i = 0; i < n; i++)
acumulador += i;
return acumulador;
}
Projeto e Análise de Algoritmos3
Estruturas de Controle
➢ Conforme visto anteriormente, para calcular a função f(n) de tempo
de um algoritmo devemos contar o números de passos elementares
do mesmo:
int soma(int n) {
int i;
int acumulador = 0;
for(i = 0; i < n; i++)
acumulador += i;
return acumulador;
}
➢ f(n) = 1 + 1 + (n+1) + 2n + 1 = 3n + 4 → O(n)
1
1
1 n+1
2n
Projeto e Análise de Algoritmos4
Estruturas de Controle
➢ Para o cálculo da complexidade não existem regras rígidas que
possam ser aplicadas a qualquer algoritmo, pois cada caso deve ser
avaliado em suas particularidades.
➢ No entanto, as estruturas de controle clássicas da programação
estruturada permitem uma estimativa típica de cada uma.
➢ Assim, os algoritmos construídos a partir de combinações dessas
estruturas podem ter sua complexidade mais facilmente
estabelecida.
Projeto e Análise de Algoritmos5
Estruturas de Controle
1. Comando simples: tem um tempo constante de execução, logo é
considerado O(1).
2. Sequência de comandos: em uma sequência, cada comando é da
ordem de O(1). Assim, a sequência é da ordem de (vide
propriedade c):
O(1) + O(1) + O(1) + ... + O(1) = O(1)
3. Comandos de seleção: deve-se calcular a complexidade de cada
uma das alternativa e usar a maior. Assim:
a) A complexidade de um IF-THEN-ELSE é a complexidade do bloco
THEN ou ELSE, a que for maior.
b) A complexidade de um SWITCH é a complexidade de um dos blocos
CASE, a que for maior.
Projeto e Análise de Algoritmos6
Estruturas de Controle
4. Comandos de repetição:
a) Se o número de iterações independe do tamanho da entrada n, então
a complexidade da repetição é a complexidade do bloco repetido (vide
propriedade b).
Exemplo:
for (int i = 1; i <= 10; i++) {
x = x + y;
printf(“%d\n”, x);
} O(1), pois o bloco 
do FOR é O(1)
Projeto e Análise de Algoritmos7
Estruturas de Controle
4. Comandos de repetição:
b) Se o número de iterações depende do tamanho da entrada n, então a
complexidade da repetição é a complexidade do bloco repetido
multiplicado pela função que descreve o número de iterações.
Exemplo 1:
for (int i = 1; i <= k * n; i++) {
x = x + i;
printf(“%d\n”, x);
}
Logo, a complexidade é (vide propriedade d):
k * n * O(1) = O(k * n * 1) = O(n)
O(1)
Número de 
iterações: k * n
Projeto e Análise de Algoritmos8
Estruturas de Controle
4. Comandos de repetição:
b) Se o número de iterações depende do tamanho da entrada n, então a
complexidade da repetição é a complexidade do bloco repetido
multiplicado pela função que descreve o número de iterações.
Exemplo 2:
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) {
x = x + i + j;
printf(“%d\n”, x);
}
Logo, a complexidade é (vide propriedade d):
n * n * O(1) = O(n * n * 1) = O(n2)
O(1)
Número de iterações: n
Número de iterações: n
Projeto e Análise de Algoritmos9
Estruturas de Controle
4. Comandos de repetição:
b) Se o número de iterações depende do tamanho da entrada n, então a
complexidade da repetição é a complexidade do bloco repetido
multiplicado pela função que descreve o número de iterações.
Exemplo 3:
limite = 1;
while (limite <= n) {
printf(“%d\n”, limite);
limite = limite * 2;
}
Como o limite dobra a cada iteração, depois de k iterações teremos:
limite = 2k ou k = log2limite
Como o valor máximo de limite é n, então o número de iterações é:
log2n
Assim, a complexidade da repetição é: log2n . O(1) = O(log(n))
O(1)
Projeto e Análise de Algoritmos10
Estruturas de Controle
4. Comandos de repetição:
b) Se o número de iterações depende do tamanho da entrada n, então a
complexidade da repetição é a complexidade do bloco repetido
multiplicado pela função que descreve o número de iterações.
Exemplo 4:
limite = n;
while (limite != 0) {
printf(“%d\n”, limite);
limite = limite / 2;
}
O limite cai à metade a cada iteração, logo teremos k iterações onde:
k = log2n
Assim, a complexidade da repetição é: log2n . O(1) = O(log(n))
O(1)
Projeto e Análise de Algoritmos11
Estruturas de Controle
5. Chamadas de funções/procedimentos: para calcular a
complexidade de um programa com várias funções, determina-se
primeiro a complexidade de cada uma das funções. Desta forma,
cada uma das funções é vista como uma instrução com a
complexidade que foi calculada.
Exemplo:
int main() {
f1();
f2();
f3();
}
Logo, a complexidade é da função main é (vide propriedade e):
O(n) + O(log n) + O(n2) = O(max(n, log n, n2)) = O(n2)
O(n)
O(log n)
O(n2)
Projeto e Análise de Algoritmos12
Estruturas de Controle
➢ Algumas fórmulas úteis:
෍
𝑖=1
𝑛
𝑖 =
𝑛(𝑛 + 1)
2
෍
𝑖=1
𝑛
𝑖 − 1 =
𝑛(𝑛 − 1)
2
෍
𝑖=1
𝑛
𝑖 + 𝑘 =
(𝑛 + 𝑘)(𝑛 + 𝑘 + 1)
2
෍
𝑖=0
𝑛
2𝑖 = 2𝑛+1 − 1
෍
𝑖=0
𝑛
1
2𝑖
= 2 −
1
2𝑛
෍
𝑖=0
𝑛
𝑎𝑖 =
𝑎𝑛+1 − 1
𝑎 − 1
(a ≠ 1)
෍
𝑖=1
𝑛
𝑖2 =
𝑛(𝑛 + 1)(2𝑛 + 1)
6
Projeto e Análise de Algoritmos13
Exercícios
➢ Exemplo 1: somatório de 1..n
int soma(int n) {
int i;
int acumulador = 0;
for(i = 1; i <= n; i++)
acumulador += i;
return acumulador;
}
Projeto e Análise de Algoritmos14
Exercícios
➢ Exemplo 1: somatório de 1..n
int soma(int n) {
int i;
int acumulador = 0;
for(i = 1; i <= n; i++)
acumulador += i;
return acumulador;
}
n repetições
→ O(1)
→ O(1)
→ O(1)
𝑂 1 + 𝑂 𝑛 + 𝑂 1 = 𝑂 max 1, 𝑛, 1 = 𝑂(𝑛)
Projeto e Análise de Algoritmos15
Exercícios
➢ Exemplo 2: inversão de um vetor
void inverte(int v[], int n) {
for(i = 0; i < n/2; i++) {
int aux = v[i];
v[i] = v[n-i-1];
v[n-i-1] = aux;
}
}
Projeto e Análise de Algoritmos16
Exercícios
➢ Exemplo 2: inversão de um vetor
void inverte(int v[], int n) {
for(i = 0; i < n/2; i++) {
int aux = v[i];
v[i] = v[n-i-1];
v[n-i-1] = aux;
}
}
3 passos: O(1)
n/2 repetições
𝑛
2
. 𝑂 1 = 𝑂
𝑛
2
. 1 = 𝑂
𝑛
2
= 𝑂(𝑛)
Projeto e Análise de Algoritmos17
Exercícios
➢ Exemplo 3: xn
long potencia(int x, int n) {
long p = 1;
for(int i = 0; i < n; i++)
p *= x;
return p;
}
Projeto e Análise de Algoritmos18
Exercícios
➢ Exemplo 3: xn
long potencia(int x, int n) {
long p = 1;
for(int i = 0; i < n; i++)
p *= x;
return p;
}
n repetições
→ O(1)
→ O(1)
→ O(1)
𝑂 1 + 𝑛.𝑂 1 + 𝑂 1 = 𝑂 1 + 𝑂 𝑛. 1 + 𝑂 1 = 𝑂 max 1, 𝑛, 1 = 𝑂(𝑛)
Projeto e Análise de Algoritmos19
Exercícios
➢ Exemplo 4:
void eureka(int n) {
int i, j;
int a = 0;
for(i = 0; i < n; i++)
for(j = n; j > i; j--)
a += i + j;
printf(“%d\n”, a);
}
Projeto e Análise de Algoritmos20
Exercícios
➢ Exemplo 4:
void eureka(int n) {
int i, j;
int a = 0;
for(i = 0; i < n; i++)
for(j = n; j > i; j--)
a += i + j;
printf(“%d\n”, a);
}
i = 0
j = n..1 (n vezes)
i = 1
j = n..2 (n-1 vezes)
i = 2
j = n..3 (n-2 vezes)
i = 3
j = n..4 (n-3 vezes)
i = n-1
j = n..n-1+1 (1 vez)
→ O(1)
𝑛 + 𝑛 − 1 + 𝑛 − 2 +⋯+ 2 + 1 =
𝑛 𝑛 + 1
2
=
𝑛2 + 𝑛
2
= 𝑂(𝑛2)
෍
𝑖=1
𝑛
𝑖 =
𝑛(𝑛 + 1)
2
Projeto e Análise de Algoritmos21
Exercícios
➢ Exemplo 5: validação de número primo
bool primo(int n) {
if(n == 2)
return true;
for(i = 2; i < n/2; i++)
if (n % i == 0)
return false;
return true;
}
Projeto e Análise de Algoritmos22
Exercícios
➢ Exemplo 5: validação de número primo
bool primo(int n) {
if (n == 2)
return true;
for(i = 2; i < n/2; i++)
if (n % i == 0)
return false;
return true;
}
n/2-2 repetições
→ O(1)
𝑛
2
− 2 . 𝑂 1 = 𝑂
𝑛
2
− 2 = 𝑂(𝑛)
Projeto e Análise de Algoritmos23
Exercícios
➢ Exemplo 6: ordenação por seleção
void ordena(int v[], int n) {
int i, j, min;
for(i = 0; i < n-1; i++) {
min = i;
for (j = i + 1; j < n; j++)
if (v[j] < v[min])
min = j;
if (min != i) {
int temp = v[min];
v[min] = v[i];
v[i] = temp;
}
}
}
Projeto e Análise de Algoritmos24
Exercícios
➢ Exemplo 6: ordenação por seleção
void ordena(int v[], int n) {
int i, j, min;
for(i = 0; i < n-1; i++) {
min = i;
for (j = i + 1; j < n; j++)
if (v[j] < v[min])
min = j;
if (min != i) {
int temp = v[min];
v[min] = v[i];
v[i] = temp;
}
}
}
n-1 repetições
n-1, n-2, n-3,...,2, 1 repetições
O(1)
O(1)
𝑛 − 1 + 𝑛 − 2 + 𝑛 − 3 +⋯+ 2 + 1 =
𝑛(𝑛 − 1)
2
=
𝑛2 − 𝑛
2
= 𝑂(𝑛2)
෍
𝑖=1
𝑛
𝑖 − 1 =
𝑛(𝑛 − 1)
2
Projeto e Análise de Algoritmos25
Exercícios
➢ Exemplo 7: multiplicação de matrizes
// Matrizes A, B e C são variáveis globais
void mult(int n) {
int i, j, k;
for(i = 0; i < n; i++)
for(j = 0; j < n; j++) {
c[i][j] = 0;
for(k = n-1; k >= 0; k--)
c[i][j] += a[i][k] * b[k][j];
}
}
Projeto e Análise de Algoritmos26
Exercícios
➢ Exemplo 7: multiplicação de matrizes
// Matrizes A, B e C são variáveis globais
void mult(int n) {
int i, j, k;
for(i = 0; i < n; i++)
for(j = 0; j < n; j++) {
c[i][j] = 0;
for(k = n-1; k >= 0; k--)
c[i][j] += a[i][k] * b[k][j];
}
}
n repetições
n repetições
n repetições
→ O(1)
𝑛. 𝑛. 𝑛. 𝑂 1 = 𝑂 𝑛3. 1 = 𝑂(𝑛3)
Projeto e Análise de Algoritmos27
Exercícios
➢ Exemplo 8:
void misterio(int n) {
int i, j, x=0, y=0;
for(i = 1; i <= n; i++) {
for(j = i; j <= n; j++) {
x++;
for(j = 1; j < i; j++)
y++;
}
}
Projeto e Análise de Algoritmos28
Exercícios
➢ Exemplo 8:
void misterio(int n) {
int i, j, x=0, y=0;
for(i = 1; i <= n; i++) {
for(j = i; j <= n; j++)
x++;
for(j = 1; j < i; j++)
y++;
}
}
n repetições
n, n-1, n-2, ..., 3, 2, 1 repetições
0, 1, 2, 3, ..., n-2, n-1 repetições
෍
𝑖=1
𝑛
𝑖 =
𝑛(𝑛 + 1)
2
෍
𝑖=1
𝑛
𝑖 − 1 =
𝑛(𝑛 − 1)
2
𝑂
𝑛(𝑛 + 1)
2
+ O
𝑛(𝑛 − 1)
2
= O 𝑚𝑎𝑥
𝑛(𝑛 + 1)
2
,
𝑛(𝑛 − 1)
2
= 𝑂(𝑛2)
Projeto e Análise de Algoritmos29
Exercícios
➢ Exemplo 9: busca binária (buscabin.cpp)
int pesqbin(int v[], int n, int k) {
int meio, ini=0, fim=n-1;
while (ini <= fim) {
meio = (ini + fim) / 2;
if (v[meio] == k)
return meio;
if (k < v[meio])
fim = meio - 1;
else
ini = meio + 1;
}
return -1;
}
1ª iteração:
ini = 0
fim = n-1
meio = (n-1)/2
Espaço de busca: fim – ini + 1 = (n-1) - 0 + 1 = n
Ou seja n elementos.
Projeto e Análise de Algoritmos30
Exercícios
➢ Exemplo 9: busca binária (buscabin.cpp)
int pesqbin(int v[], int n, int k) {
int meio, ini=0, fim=n-1;
while (ini <= fim) {
meio = (ini + fim) / 2;
if (v[meio] == k)
return meio;
if (k < v[meio])
fim = meio - 1;
else
ini = meio + 1;
}
return -1;
}
2ª iteração:
ini = 0
fim = meio–1 = (n-1)/2-1
meio = ((n-1)/2-1)/2
OU
ini = meio+1 = (n-1)/2+1
fim = n-1
meio = (((n-1)/2+1) + (n-1))/2
Espaço de busca: (n-1)/2 - 1 - 0 + 1 = (n-1)/2
Ou seja, n/2 elementos.
Projeto e Análise de Algoritmos31
Exercícios
➢ Exemplo 9: busca binária (buscabin.cpp)
int pesqbin(int v[], int n, int k) {
int meio, ini=0, fim=n-1;
while (ini <= fim) {
meio = (ini + fim) / 2;
if (v[meio] == k)
return meio;
if (k < v[meio])
fim = meio - 1;
else
ini = meio + 1;
}
return -1;
}
3ª iteração:
ini = 0
fim = meio-1 = (((n-1)/2-1)/2) – 1
meio = ((((n-1)/2-1)/2) – 1) / 2
OU
ini = meio+1 = (((n-1)/2+1) + (n-1))/2 + 1
fim = n-1
Meio = (((((n-1)/2+1) + (n-1))/2 + 1) + (n-1)) / 2
Espaço de busca: (((n-1)/2-1)/2) – 1 – 0 + 1 = ((n-1)/2-1)/2 =
= (n-3)/4
Ou seja, n/4 elementos.
Projeto e Análise de Algoritmos32
Exercícios
➢ Exemplo 9: busca binária (buscabin.cpp)
int pesqbin(int v[], int n, int k) {
int meio, ini=0, fim=n-1;
while (ini <= fim) {
meio = (ini + fim) / 2;
if (v[meio] == k)
return meio;
if (k < v[meio])
fim = meio - 1;
else
ini = meio + 1;
}
return -1;
}
Assim, a cada iteração o espaço de busca é
reduzido à metade.
Na iteração k teremos
𝒏
𝟐𝒌−𝟏
elementos no espaço
de busca.
Iteração Espaço de busca
1 n = n/20
2 n/2 = n/21
3 n/4 = n/22
4 n/8 = n/23
... ...
k n/2k-1
Projeto e Análise de Algoritmos33
Exercícios
➢ Exemplo 9: busca binária (buscabin.cpp)
int pesqbin(int v[], int n, int k) {
int meio, ini=0, fim=n-1;
while (ini <= fim) {
meio = (ini + fim) / 2;
if (v[meio] == k)
return meio;
if (k < v[meio])
fim = meio - 1;
else
ini = meio + 1;
}
return -1;
}
Pergunta-se: dado um inteiro n > 0, quantas
iterações são necessárias para dividir n à
metade até atingir 1?
𝑛
2𝑘−1
= 1 ֜ 𝑛 = 2𝑘−1 ֜ 𝑙𝑜𝑔2𝑛 = 𝑙𝑜𝑔22
𝑘−1
֜ 𝑙𝑜𝑔2𝑛 = 𝑘 − 1 ֜ 𝑘 = 𝑙𝑜𝑔2𝑛 + 1
Ou seja, log2n + 1 iterações.
Projeto e Análise de Algoritmos34
Exercícios
➢ Exemplo 9: busca binária (buscabin.cpp)
int pesqbin(int v[], int n, int k) {
int meio, ini=0, fim=n-1;
while (ini <= fim) {
meio = (ini + fim) / 2;
if (v[meio] == k)
return meio;
if (k < v[meio])
fim = meio - 1;
else
ini = meio + 1;
}
return -1;
}
O(1)
log2n + 1 repetições
𝑙𝑜𝑔2𝑛 + 1 .𝑂 1 = 𝑂 𝑙𝑜𝑔2𝑛 + 1 = 𝑂(log 𝑛)
Projeto e Análise de Algoritmos35
Recursividade
➢ Todo algoritmo recursivo é composto de:
a) Um ou mais casos-base (situações onde o algoritmo atinge uma
solução trivial).
b) Uma ou mais chamadas recursivas (definição da solução em função
dela mesma).
int fat(int n) {
if (n == 0)
return 1;
return n * fat(n-1);
}
Caso-base
Definição recursiva
Projeto e Análise de Algoritmos36
Recursividade
➢ Analisando a função de tempo f do algoritmo abaixo, temos:
int fat(int n) {
if (n == 0)
return 1;
return n * fat(n-1);
}
Para o caso-base 
temos 2 passos.
𝑓 𝑛 = 2 , 𝑠𝑒 𝑛 = 0
Projeto e Análise de Algoritmos37
Recursividade
➢ Analisando a função de tempo f do algoritmo abaixo, temos:
int fat(int n) {
if (n == 0)
return 1;
return n * fat(n-1);
}
Para a recursão temos 4 passos
mais os passos relativos à 
chamada recursiva.
𝑓 𝑛 = 2 , 𝑠𝑒 𝑛 = 0
𝑓 𝑛 = 𝑓 𝑛 − 1 + 4, 𝑠𝑒 𝑛 > 0
Para calcular a complexidade 
devemos resolver essa equação 
de recorrência!
Projeto e Análise de Algoritmos38
Recursividade
➢ Resolver uma equação de recorrência nem sempre é fácil.
➢ Algumas técnicas:
✓ Método da iteração: expande a recorrência e usa propriedades
algébricas para encontrar e resolver um somatório.
✓ Método da substituição: pressupõe uma solução e usa indução
matemática para verificar se a suposição se aplica.
✓ Método da árvore de recursão: é um método intuitivo que
consiste e desenhar uma árvore cujos nós representam o custo
nos diversos níveis da recursão.
✓ Método mestre: teorema que define como resolver equações de
recorrência que seguem determinados padrões.
Projeto e Análise de Algoritmos39
Recursividade
➢ Aplicando o método da iteração:
f(n) = f(n-1) + 4
f(n) = f(n-2) + 4+ 4
f(n) = f(n-3) + 4 + 4 + 4
f(n) = f(n-4) + 4 + 4 + 4 + 4
f(n) = f(n-5) + 4 + 4 + 4 + 4 + 4
...
f(n) = f(n-k) + 4k
Caso-base é alcançado quando n - k = 0, ou seja, k = n:
f(n) = f(n-n) + 4n
f(n) = 4n + 2 = O(n)
𝑓 𝑛 = 2 , 𝑠𝑒 𝑛 = 0
𝑓 𝑛 = 𝑓 𝑛 − 1 + 4, 𝑠𝑒 𝑛 > 0
O 4 é somado k vezes.
Projeto e Análise de Algoritmos40
Recursividade
➢ Outra forma de resolver:
f(n) = f(n-1) + 4
f(n-1) = f(n-2) + 4
f(n-2) = f(n-3) + 4
f(n-3) = f(n-4) + 4
f(n-4) = f(n-5) + 4
...
f(n-n+1) = f(n-n) + 4
Somando os termos dos lados direito e esquerdo:
f(n) + f(n-1) + f(n-2) + f(n-3) + f(n-4) +...+f(1) = f(n-1) + f(n-2) + f(n-3) + f(n-
4) +...+f(1) + f(0) + 4 + 4 + 4 +...+ 4
f(n) = f(0) + 4n
f(n) = 4n + 2 = O(n)
𝑓 𝑛 = 2 , 𝑠𝑒 𝑛 = 0
𝑓 𝑛 = 𝑓 𝑛 − 1 + 3, 𝑠𝑒 𝑛 > 0
O 4 é somado n vezes.
Projeto e Análise de Algoritmos41
Recursividade
➢ Torre de Hanoi (hanoi.cpp):
void hanoi(int discos, int origem, int destino, int aux) {
if (discos == 1) {
printf(“Mover 1 disco de %d para %d\n”, origem, destino);
return;
}
hanoi(discos-1, origem, aux, destino);
printf(“Mover 1 disco de %d para %d\n”, origem, destino);
hanoi(discos-1, aux, destino, origem);
}
𝑓 𝑛 = 3 , 𝑠𝑒 𝑛 = 1
Projeto e Análise de Algoritmos42
Recursividade
➢ Torre de Hanoi (hanoi.cpp):
void hanoi(int discos, int origem, int destino, int aux) {
if (discos == 1) {
printf(“Mover 1 disco de %d para %d\n”, origem, destino);
return;
}
hanoi(discos-1, origem, aux, destino);
printf(“Mover 1 disco de %d para %d\n”, origem, destino);
hanoi(discos-1, aux, destino, origem);
}
𝑓 𝑛 = 3 , 𝑠𝑒 𝑛 = 1
𝑓 𝑛 = 2. 𝑓 𝑛 − 1 + 4, 𝑠𝑒 𝑛 > 1
Projeto e Análise de Algoritmos43
Recursividade
➢ Aplicando o método da iteração:
f(n) = 2.f(n-1) + 4
f(n) = 2.(2.f(n-2) + 4) + 4 = 4.f(n-2) + 8 + 4
f(n) = 4.(2.f(n-3) + 4) + 8 + 4 = 8.f(n-3) + 16 + 8 + 4
f(n) = 8.(2.f(n-4) + 4) + 16 + 8 + 4 = 16.f(n-4) + 32 + 16 + 8 + 4
f(n) = 16.(2.f(n-5) + 4) + 32 + 16 + 8 + 4 = 32.f(n-5) + 64 + 32 + 16 + 8 + 4
...
f(n) = 2k.f(n-k) + σ𝑖=2
𝑘+12𝑖
Caso-base é alcançado quando k = n-1:
f(n) = 2n-1.f(1) + σ𝑖=2
𝑛 2𝑖
f(n) = 2n-1 . 3 + 2n+1 – 4 = (2+1) 2n-1 + 2n+1 – 2
= 2n+ 2n-1 + 2n+1 – 2 = 2n+1+ 2n+2n-1 – 4 = O(2n)
𝑓 𝑛 = 3 , 𝑠𝑒 𝑛 = 1
𝑓 𝑛 = 2. 𝑓 𝑛 − 1 + 4, 𝑠𝑒 𝑛 > 1
෍
𝑖=0
𝑛
𝑎𝑖 =
𝑎𝑛+1 − 1
𝑎 − 1
(a ≠ 1)
Projeto e Análise de Algoritmos44
Recursividade
➢ Torre de Hanoi (hanoi.cpp):
void hanoi(int discos, int origem, int destino, int aux) {
if (discos == 1) {
printf(“Mover 1 disco de %d para %d\n”, origem, destino);
return;
}
hanoi(discos-1, origem, aux, destino);
printf(“Mover 1 disco de %d para %d\n”, origem, destino);
hanoi(discos-1, aux, destino, origem);
}
𝑓 𝑛 = 𝑂 1 , 𝑠𝑒 𝑛 = 1
𝑓 𝑛 = 2. 𝑓 𝑛 − 1 + 𝑂(1), 𝑠𝑒 𝑛 > 1
Projeto e Análise de Algoritmos45
Recursividade
➢ Aplicando o método da iteração:
f(n) = 2.f(n-1)
f(n) = 2.(2.f(n-2)) = 4.f(n-2)
f(n) = 4.(2.f(n-3)) = 8.f(n-3)
f(n) = 8.(2.f(n-4)) = 16.f(n-4)
f(n) = 16.(2.f(n-5)) = 32.f(n-5)
...
f(n) = 2k.f(n-k)
Caso-base é alcançado quando k = n-1:
f(n) = 2n-1.O(1)
f(n) = 2n-1 = O(2n)
𝑓 𝑛 = 𝑂(1) , 𝑠𝑒 𝑛 = 1
𝑓 𝑛 = 2. 𝑓 𝑛 − 1 + 2, 𝑠𝑒 𝑛 > 1
Projeto e Análise de Algoritmos46
Recursividade
➢ Fibonacci recursivo (fibonacci.cpp):
int fib(int n) {
if (n == 1)
return 0;
if (n == 2)
return 1;
return fib(n-1) + fib(n-2);
}
𝑓 𝑛 = 2 , 𝑠𝑒 𝑛 = 1
𝑓 𝑛 = 3 , 𝑠𝑒 𝑛 = 2
𝑓 𝑛 = 𝑓 𝑛 − 1 + 𝑓 𝑛 − 2 + 6, 𝑠𝑒 𝑛 > 2
Projeto e Análise de Algoritmos47
Recursividade
➢ Aplicando o método da iteração:
f(n) = f(n-1) + f(n-2)
f(n) = f(n-2)+f(n-3) + f(n-3)+f(n-4)
= f(n-2) + 2.f(n-3) + f(n-4)
f(n) = f(n-3)+f(n-4) + 2.f(n-4)+2.f(n-5) + f(n-5)+f(n-6)
= f(n-3) + 3.f(n-4) + 3.f(n-5) + f(n-6)
f(n) = f(n-4)+f(n-5) + 3.f(n-5)+3.f(n-6) + 3.f(n-6)+3.f(n-7) + f(n-7)+f(n-8)
= f(n-4) + 4.f(n-5) + 6.f(n-6) + 4.f(n-7) + f(n-8)
f(n) = f(n-5)+f(n-6) + 4.f(n-6)+4.f(n-7) + 6.f(n-7)+6.f(n-8) + 4.f(n-8)+4.f(n-9) +
f(n-9)+f(n-10)
= f(n-5) + 5.f(n-6) + 10.f(n-7) + 10.f(n-8) + 5.f(n-9) + f(n-10)
𝑓 𝑛 = 𝑂 1 , 𝑠𝑒 𝑛 = 1
𝑓 𝑛 = 𝑂(1) , 𝑠𝑒 𝑛 = 2
𝑓 𝑛 = 𝑓 𝑛 − 1 + 𝑓 𝑛 − 2 + 𝑂(1), 𝑠𝑒 𝑛 > 2
Onde está a equação geral?
Projeto e Análise de Algoritmos48
Recursividade
➢ Aplicando o método da substituição (prova por indução):
➢ Assuma que o algoritmo é O(2n), ou seja:
𝑓 𝑛 ≤ 2𝑛
➢ Hipótese: 𝑓 𝑛 ≤ 2𝑛 é verdade para n=1, 2, 3,..., k.
➢ Provar que essa relação vale para k+1: 𝑓 𝑘 + 1 ≤ 2𝑘+1
Projeto e Análise de Algoritmos49
Recursividade
➢ Provar que essa relação vale para k+1: 𝑓 𝑘 + 1 ≤ 2𝑘+1
𝑓 𝑘 + 1 ≤ 𝑓 𝑘 + 𝑓(𝑘 − 1)
𝑓 𝑘 + 1 ≤ 2𝑘 + 2𝑘−1
𝑓 𝑘 + 1 ≤
2
2
2𝑘 +
22
22
2𝑘−1
𝑓 𝑘 + 1 ≤
2𝑘+1
2
+
2𝑘+1
4
𝑓 𝑘 + 1 ≤
1
2
2𝑘+1 +
1
4
2𝑘+1
𝑓 𝑘 + 1 ≤ 2𝑘+1
1
2
+
1
4
𝑓 𝑘 + 1 ≤
3
4
2𝑘+1 , 𝑐𝑜𝑚𝑜
3
4
< 1 𝑒𝑛𝑡ã𝑜 𝑓 𝑘 + 1 ≤ 2𝑘+1
Assim, o algoritmo recursivo é O(2n).
Projeto e Análise de Algoritmos50
Recursividade
➢ Para ser exato, já foi provado que a complexidade do Fibonacci
recursivo é:
𝑓 𝑛 = 𝑂
1 + 5
2
𝑛
= 𝑂 1,618033…𝑛 𝑛՜∞
➢ Ou seja, a complexidade desse algoritmo é realmente exponencial!

Outros materiais