Tutoria AEDSI
Pablo Silva
Mais de recursividade
Vamos ver mais alguns exemplos de problemas que
podemos resolver com recursividade
Seja o problema em que temos um número
natural n >= 0 e queremos descobrir a soma
de todos os números de n até 0. Como
resolver este problema recursivamente?
Entender o problema matemático
Precisamos sempre encontrar o caso base e o passo
recursivo. Mas para isso, temos que entender o
problema matemático.
Entender o problema matemático
Vejamos possíveis iterações:
0 = 0
1 = 1 + 0 = 1
2 = 2 + 1 + 0 = 3
3 = 3 + 2 + 1 + 0 = 6
...
n = n + n-1 + n-2 + ... + 0
O caso base como podemos
perceber é zero, pois é sempre
onde o problema termina!
Entender o problema matemático
Vejamos possíveis iterações:
0 = 0
1 = 1 + 0 = 1
2 = 2 + 1 + 0 = 3
3 = 3 + 2 + 1 + 0 = 6
...
n = n + n-1 + n-2 + ... + 0
O que podemos perceber
analisando as iterações, é que
começamos a somar em n e
vamos diminuindo em 1 para
cada número natural anterior a
n até zero.
n-1
Entender o problema matemático
Se assumirmos que diminuímos o problema em um fator de 1, então
teríamos a seguinte situação:
0 = 0
1 = + 0 = 1
2 = + 1 + 0 = 3
3 = + 2 + 1 + 0 = 6
...
n = + n + n-1 + ... + 0
Ao diminuirmos, percebemos que
novamente, nessa iteração, teríamos após o
n, um fator n-1 e então podemos definir
nosso passo recursivo como:
n + soma(n-1)
Pois para resolver o problema, sempre
somamos n com o seu antecessor direto (n-
1).
n-1
Soma de n termos
Nossa função então ficaria da seguinte forma:
int soma(int n){
if(n == 0)
return 0;
return n + soma(n-1);
}
Mais um exemplo
Seja o problema de elevar qualquer número n á um expoente qualquer k.
Como resolver isso de maneira recursiva. Vamos ver algumas possíveis
interações deste problema matemático, com n = 2 e k >= 0:
20
= 1
21
= 2 ∗ 20
22
= 2 ∗ 2 ∗ 20
= 2 ∗ 21
23
= 2 ∗ 2 ∗ 2 ∗ 20
= 2 ∗ 22
24
= 2 ∗ 21
∗ 21
∗ 21
∗ 20
= 2 ∗ 23
Na multiplicação de mesma base podemos somar os
expoentes e manter a base (1+1+1+0 = 3)
K - 1 Percebemos que o
problema termina sempre
que k = 0. Portanto, desta
vez, a diminuição do nosso
problema, ocorrerá no
expoente e não no número
que estamos somando.
Um fato importante a se considerar
sobre recursão
- Nós podemos ter mais de um caso base!
- Sempre precisamos encontrar uma maneira de diminuir o problema. O
fator que vamos diminuir e qual é o nosso parâmetro de diminuição não
será o mesmo para todos os problemas. Podemos, inclusive, ter que
diminuir o problema utilizando mais que um parâmetro para isso.
- É importante notar que o fator de diminuição nem sempre será em 1,
pode por exemplo ser 2 ou até mesmo dividir o problema pela metade
a cada passo recursivo!
Mais um exemplo
Seja o problema de elevar qualquer número n á um expoente qualquer k.
Como resolver isso de maneira recursiva. Vamos ver algumas possíveis
interações deste problema matemático, com n = 2 e k >= 0:
20
= 1
21
= 2 ∗ 20
22
= 2 ∗ 2 ∗ 20
= 2 ∗ 21
23
= 2 ∗ 2 ∗ 2 ∗ 20
= 2 ∗ 22
24
= 2 ∗ 21
∗ 21
∗ 21
∗ 20
= 2 ∗ 23
Na multiplicação de mesma base podemos somar os
expoentes e manter a base (1+1+1+0 = 3)
K - 1 O caso base é fácil de
perceber, pois quando k =
0, o problema terminou
para todas as iterações.
Logo k = 0 é o nosso caso
base.
Mais um exemplo
Seja o problema de elevar qualquer número n á um expoente qualquer k.
Como resolver isso de maneira recursiva. Vamos ver algumas possíveis
interações deste problema matemático, com n = 2 e k >= 0:
20
= 1
21
= 2 ∗ 20
22
= 2 ∗ 2 ∗ 20
= 2 ∗ 21
23
= 2 ∗ 2 ∗ 2 ∗ 20
= 2 ∗ 22
24
= 2 ∗ 21
∗ 21
∗ 21
∗ 20
= 2 ∗ 23
Na multiplicação de mesma base podemos somar os
expoentes e manter a base (1+1+1+0 = 3)
K - 1 Para o passo recursivo,
percebemos que sempre
podemos multiplicar n por
uma potenciação de 𝑛 𝑘−1.
O k-1 é em relação ao
expoente inicial. Logo o
passo recursivo:
𝑛 * 𝑛 𝑘−1
Potenciação recursiva
Nossa função então ficaria da seguinte forma:
int pot(int n, int k){
if(k == 0)
return 1;
return n * pot(n,k-1);
}
Análise da recursividade
Qual é a complexidade do algoritmo recursivo que
calcula o fatorial de n? Como conseguimos calcular
esse valor?
Análise da recursividade
Analisar a complexidade de algoritmos recursivos
não é tão simples assim e muitas vezes temos que
utilizar recursos matemáticos mais aguçados para
conseguir chegar à um valor.
Análise da recursividade
Analisar a complexidade de algoritmos recursivos
não é tão simples assim e muitas vezes temos que
utilizar recursos matemáticos mais aguçados para
conseguir chegar à um valor. Isto envolve saber a
descrição matemática que nos dá o
comportamento do algoritmo, que será definida
como sua relação de recorrência! (recorrência, pois o algoritmo sempre
“recorre” a si mesmo várias vezes para resolver um problema qualquer. Recorrência é o mesmo que repetição!)
Relações de recorrência
Uma relação de recorrência é sempre formada por:
o caso base e por um elemento que se parece
muito com o passo recursivo, mas tem a ver com
número de operações completadas. Vamos tentar
entender um pouco deste elemento, utilizando o
fatorial recursivo de n.
Relações de recorrência
Seja uma relação de recorrência representada pelo
símbolo 𝑇, podemos definir então a função de 𝑇(n),
que será a função que descreverá nossa relação de
recorrência, de modo que:
𝑇 𝑛 =
𝐶 , 𝑞𝑢𝑎𝑛𝑑𝑜 𝑛 𝑎𝑡𝑖𝑛𝑔𝑒 𝑜 𝑐𝑎𝑠𝑜 𝑏𝑎𝑠𝑒
𝑇 𝑛 𝑝𝑜𝑟 𝑎𝑙𝑔𝑢𝑚 𝑓𝑎𝑡𝑜𝑟 𝑑𝑒 𝑘 + 𝑑 𝑑 ≥< 0
Onde o valor mínimo de n depende do nosso problema matemático!
Relações de recorrência
Vamos utilizar como exemplo o fatorial de n.
Sabemos que o caso base é quando n = 1 e neste
caso, o valor retornado é 1. Logo C = 1 quando n = 1,
então:
𝑇 𝑛 =
1 , 𝑠𝑒 𝑛 = 1
Relações de recorrência
Agora vamos analisar a função fatorial, para encontrar nossa
relação de recorrência:
int fatorial(int n){
if( n == 1 )
return 1;
return n * fatorial(n-1);
}
Para encontrar a recorrência do algoritmo temos
que nos atentar para o número de operações
que temos a cada passo. Olhando para o passo
recursivo, pode-se perceber que sempre vamos
ter 1 multiplicação mais uma chamada da função
fatorial com o nosso problema diminuído em 1.
Portanto nossa recorrência pode ser definida
por:
1 + 𝑇 𝑛 − 1
Onde T refere-se neste caso a função fatorial!
Uma multiplicação e uma
chamada de função com o
problema diminuído em 1!
Relações de recorrência
Logo, k = 1, o fator de diminuição é uma subtração
por k e d = 1, que é o valor de operações
completadas por cada chamada da função.
𝑇 𝑛 =
1 , 𝑠𝑒 𝑛 = 1
𝑇 𝑛 − 1 + 1 ,
Relações de recorrência
Para finalizar o nosso T(n), precisamos definir o valor
mínimo que n atinge em que a recorrência ainda
existe. Neste caso, é todo valor que n assume que é
maior que o caso base. Logo
𝑇 𝑛 =
1 , 𝑠𝑒 𝑛 = 1
𝑇 𝑛 − 1 + 1 , 𝑝𝑎𝑟𝑎 𝑛 > 1
Quando n atingir 1, não teremos mais recorrências!
Como resolver uma relação de recorrência?
Temos duas maneiras de resolver uma relação de
recorrência:
- Por expansão dos fatores
- Por indução matemática
Resolvendo recorrências por expansão de
fatores. Receita de bolo!
1º) Copie a fórmula original
𝑇 𝑛 = 𝑇 𝑛 − 1 + 1
2º) Descubra por quanto que a recorrência é diminuída a cada passo (fator de
diminuição k)
T(n) está escrito em função de T(n-1) então a cada passo o parâmetro n é
subtraído de 1 (k = 1)
Resolvendo recorrências por expansão de
fatores. Receita de bolo!
3º) Encontre o valor de T para os próximos valores da diminuição,
utilizando valor da equação original T(n) = T(n – 1) + 1
Como já sabemos que o fator de diminuição é subtraído de 1, então
devemos achar os valores de T(n-1), T(n-2), T(n-3) e assim por diante,
substituindo n pelos respectivos valores na equação inicial.
Resolvendo recorrências por expansão de
fatores. Receita de bolo!
3º) Encontre o valor de T para os próximos valores da diminuição,
utilizando valor da equação original T(n) = T(n – 1) + 1
Se ainda está confuso o que devemos fazer, pense nesse problema
matemático, seja:
𝑓 𝑥 = 2𝑥
Se queremos saber o valor de f(2) e f(3) logo x = 2, x = 3, então fazemos:
𝑓 2 = 2 ∗ 2 = 4
𝑓 3 = 2 ∗ 3 = 6
Resolvendo recorrências por expansão de
fatores. Receita de bolo!
3º) Encontre o valor de T para os próximos valores da diminuição, utilizando valor
da equação original T(n) = T(n – 1) + 1
Portanto se queremos saber os valores de T(n-1), T(n-2)... Então n = n-1, n = n-2,...
E fazemos como anteriormente substituindo os valores de n. Logo:
𝑇 (𝑛 − 1) = 𝑇 𝑛 − 1 − 1 + 1 = T n − 2 + 1 (3.1)
𝑇 (𝑛 − 2) = 𝑇 𝑛 − 2 − 1 + 1 = T n − 3 + 1(3.2)
𝑇 (𝑛 − 3) = 𝑇 𝑛 − 3 − 1 + 1 = T n − 4 + 1(3.3)
Resolvendo recorrências por expansão de
fatores. Receita de bolo!
4º) Substitua os valores encontrados em 3, na equação original (chamamos isto de
expansão da recorrência) T(n) = T(n-1) + 1
Utilizando 3.1, onde encontramos o valor de T(n-1):
𝑇 𝑛 = 𝑇 𝑛 − 2 + 1 + 1 ⇒ 𝑇 𝑛 = 𝑇 𝑛 − 2 + 2 (4.1)
Utilizando 3.2, onde encontramos o valor de T(n-2), substituímos em 4.1
𝑇 𝑛 = 𝑇 𝑛 − 3 + 1 + 2 ⇒ 𝑇 𝑛 = 𝑇 𝑛 − 3 + 3 (4.2)
k
k
Resolvendo recorrências por expansão de
fatores. Receita de bolo!
4º) Continuamos a substituir, até conseguirmos enxergar um padrão nas expansões:
Utilizando 3.2, onde encontramos o valor de T(n-3), substituímos em 4.2:
𝑇 𝑛 = 𝑇 𝑛 − 4 + 1 + 3 ⇒ 𝑇 𝑛 = 𝑇 𝑛 − 4 + 4 (4.3)
Podemos notar que o valor de k incrementa a cada expansão, que é o comportamento
experado, já que estamos sempre diminuindo a recorrência pelo fator de 1 (valor inicial
de k). A ideia é perceber o comportamento da recorrência ao se aumentar o valor de k
(diminuir a recorrência)!
k
Resolvendo recorrências por expansão de
fatores. Receita de bolo!
4º) Analisando todas as iterações:
𝑇 𝑛 = 𝑇 𝑛 − 2 + 2 (4.1)
𝑇 𝑛 = 𝑇 𝑛 − 3 + 3 4.2
𝑇 𝑛 = 𝑇 𝑛 − 4 + 4 4.3
k
A cada expansão da recorrência, k assume um novo valor. Percebemos também que o valor constante que é
somado a recorrência e indica a quantidade de multiplicações que teremos que realizar para encontrar a
solução do problema (fatorial de n) é o mesmo valor de k em todas as iterações.
Resolvendo recorrências por expansão de
fatores. Receita de bolo!
4º) Analisando todas as iterações:
𝑇 𝑛 = 𝑇 𝑛 − 2 + 2 (4.1)
𝑇 𝑛 = 𝑇 𝑛 − 3 + 3 4.2
𝑇 𝑛 = 𝑇 𝑛 − 4 + 4 4.3
k
Logo, depois de k expansões teremos:
𝑇 𝑛 = 𝑇 𝑛 − 𝑘 + 𝑘
Resolvendo recorrências por expansão de
fatores. Receita de bolo!
5º) Encontrar quando a expansão para. Precisamos pensar no caso base, que é o
mesmo que pensar em quando T(n-k) nos retornará um valor. Olhando para o caso
base, sabemos que teremos um valor de retorno e não uma nova recorrência quando n
= 1. Para o nosso caso, n = (n-k) que é o valor de argumento da recorrência [T(n-k)]
𝑇 𝑛 = 𝑇 𝑛 − 𝑘 + 𝑘 (5.1)
Logo precisamos saber quando n-k = 1, pois então teremos T(1) e já sabemos que isso é
igual a 1.
𝑛 − 𝑘 = 1 ⇒ 𝑘 = 𝑛 − 1
Resolvendo recorrências por expansão de
fatores. Receita de bolo!
5º) Substituindo o valor de k encontrado (n-1) em 5.1 temos
𝑇 𝑛 = 𝑇 𝑛 − (𝑛 − 1) + 𝑛 − 1
= 𝑇 1 + 𝑛 − 1
Como sabemos que T(1) = 1, então
𝑇 𝑛 = 1 + 𝑛 − 1
𝑇 𝑛 = 𝑛
Resolvendo recorrências por expansão de
fatores. Receita de bolo!
6º) Definir o limite assintótico de T(n)
Como encontramos que T(n) = n, então neste caso sabemos que o algoritmo fatorial de
n recursivo é O(n), maior grau no polinômio encontrado.
Na prática, depois de várias décadas de estudo, sabe-se que o resultado da relação de
recorrência é suficiente para conhecer a complexidade do algoritmo, porém se
quisermos realmente provar (e às vezes isso será necessário!), precisamos utilizar
indução matemática, que é um método da matemática discreta que nos ensina como
provar problemas matemáticos, entre eles relações de recorrência.
Resolvendo recorrências por expansão de
fatores. Receita de bolo!
6º) Definir o limite assintótico de T(n)
Como encontramos que T(n) = n, então neste caso sabemos que o algoritmo fatorial de
n recursivo é O(n), maior grau no polinômio encontrado.
Na prática, depois de várias décadas de estudo, sabe-se que o resultado da relação de
recorrência é suficiente para conhecer a complexidade do algoritmo, porém se
quisermos realmente provar (e às vezes isso será necessário!), precisamos utilizar
indução matemática, que é um método da matemática discreta que nos ensina como
provar problemas matemáticos, entre eles relações de recorrência.
Indução matemática
Em uma linguagem bem simplificada. Você pode usar a indução
matemática para provar uma expressão matemática quando:
1 – Sabe que ela é verdadeira para algum valor.
2 – Quer provar que ela é válida então para esse valor em
relação a um fator de um (pode ser aumentar ou diminuir). Ou
seja, quer provar que o próximo valor e os próximos valores
depois deste também são verdadeiros.
Indução matemática
Características:
1 – O passo 1 do slide anterior é chamado de passo base.
2 – O passo 2 é o passo indutivo.
Indução matemática
Exemplo. Seja um teorema que tenha como parâmetro um número
natural n. Provando que T é válido para todos os valores de n,
provamos que:
1 – T é válido para n = 1 (eu tenho que saber que isto é verdade!);
2 – Para todo n > 1, se T é válido para n – 1, então T é válido para n
(Se conseguirmos provar que n – 1 é válido (e isto implica em provar
que n – 2, n – 3 e assim por diante também é válido), então podemos
provar que n é verdadeiro. Esse é o passo indutivo.
O que é uma prova?
Em matemática, uma prova é uma argumentação
precisa que procura convencer o leitor de que uma
certa preposição, previamente enunciada está
correta. Num sentindo mais informa, uma prova é
um texto que ajuda o leitor a entender por que
uma dada afirmação é verdadeira!
Provando uma relação de recorrência por indução
matemática
Primeiro temos que provar que o passo base é verdadeiro. Para
nossa equação de recorrência do problema do fatorial:
𝑇 𝑛 =
1 , 𝑠𝑒 𝑛 = 1
𝑇 𝑛 − 1 + 1 , 𝑝𝑎𝑟𝑎 𝑛 > 1
Logo primeiro queremos provar que T(1) = 1. Sabemos que T(1)
é verdadeiro, pois quando n = 1, o algoritmo não realiza
nenhuma multiplicação. Logo, o nosso caso base é verdadeiro!
Provando uma relação de recorrência por indução
matemática
Agora supomos que T(k) = k (pois não sabemos quanto é
realmente este valor antes de calcular todas as multiplicações. A
variável n foi substituída por k, pois estamos generalizando para
quaisquer valores n > 1, pois quando n = 1 já provamos ser
verdadeiro). Para provar que T(k) = k é verdadeiro, precisamos
provar que T(k + 1) = k + 1 também é verdadeiro. Se
conseguirmos provar que T(k + 1) é verdadeiro, então T(k)
também será verdadeiro, pois derivamos T(k+1) de T(k) e assim
nosso passo indutivo seria verdadeiro e nossa relação de
recorrência também.
Provando uma relação de recorrência por indução
matemática
A ideia principal aqui é a seguinte. Vamos encontrar definir
nossa hipótese de indução. A hipótese de indução é sempre
nosso passo recursivo:
𝑇 𝑛 = 𝑇 𝑛 − 1 + 1
Vamos a partir da nossa hipótese de indução, determinar o valor
de T(k + 1).
Provando uma relação de recorrência por indução
matemática
𝑇 𝑘 + 1 = 𝑇 (𝑘 + 1) − 1 + 1
= 𝑇 𝑘 + 1
Sempre, que queremos provar T(k+1), precisamos tentar deixá-lo
em função de T(k), que é o valor que supomos no começo do
exercício que queríamos provar. Supomos que T(k) = k, então
vamos substituí-lo na expressão encontrada acima.
Provando uma relação de recorrência por indução
matemática
Como supomos que T(k) = k no começo do exercícios,
podemos então substituí-lo na expressão encontrada no slide
anterior:
𝑇 𝑘 + 1 = 𝑇 𝑘 + 1
T(k + 1) = 𝑘 + 1
Note que é exatamente o que queríamos provar, pois lembre-se
que no começo do exercício, supomos T(k) = k e queríamos
provar que T(k+1) = k +1.
Provando uma relação de recorrência por indução
matemática
Escrever uma prova de indução matemática sempre envolve:
- Provar o caso base
- Supor T(k) = k e tentar provar que T(k+1) = k+1
- Encontrar uma hipótese de indução, que é o nosso passo
recursivo
- Utilizar a hipótese de indução para encontrar T(k+1) em
função de T(k)
- Manipular T(k+1) para que ele seja k+1

Relações de recorrência

  • 1.
  • 2.
    Mais de recursividade Vamosver mais alguns exemplos de problemas que podemos resolver com recursividade
  • 3.
    Seja o problemaem que temos um número natural n >= 0 e queremos descobrir a soma de todos os números de n até 0. Como resolver este problema recursivamente?
  • 4.
    Entender o problemamatemático Precisamos sempre encontrar o caso base e o passo recursivo. Mas para isso, temos que entender o problema matemático.
  • 5.
    Entender o problemamatemático Vejamos possíveis iterações: 0 = 0 1 = 1 + 0 = 1 2 = 2 + 1 + 0 = 3 3 = 3 + 2 + 1 + 0 = 6 ... n = n + n-1 + n-2 + ... + 0 O caso base como podemos perceber é zero, pois é sempre onde o problema termina!
  • 6.
    Entender o problemamatemático Vejamos possíveis iterações: 0 = 0 1 = 1 + 0 = 1 2 = 2 + 1 + 0 = 3 3 = 3 + 2 + 1 + 0 = 6 ... n = n + n-1 + n-2 + ... + 0 O que podemos perceber analisando as iterações, é que começamos a somar em n e vamos diminuindo em 1 para cada número natural anterior a n até zero. n-1
  • 7.
    Entender o problemamatemático Se assumirmos que diminuímos o problema em um fator de 1, então teríamos a seguinte situação: 0 = 0 1 = + 0 = 1 2 = + 1 + 0 = 3 3 = + 2 + 1 + 0 = 6 ... n = + n + n-1 + ... + 0 Ao diminuirmos, percebemos que novamente, nessa iteração, teríamos após o n, um fator n-1 e então podemos definir nosso passo recursivo como: n + soma(n-1) Pois para resolver o problema, sempre somamos n com o seu antecessor direto (n- 1). n-1
  • 8.
    Soma de ntermos Nossa função então ficaria da seguinte forma: int soma(int n){ if(n == 0) return 0; return n + soma(n-1); }
  • 9.
    Mais um exemplo Sejao problema de elevar qualquer número n á um expoente qualquer k. Como resolver isso de maneira recursiva. Vamos ver algumas possíveis interações deste problema matemático, com n = 2 e k >= 0: 20 = 1 21 = 2 ∗ 20 22 = 2 ∗ 2 ∗ 20 = 2 ∗ 21 23 = 2 ∗ 2 ∗ 2 ∗ 20 = 2 ∗ 22 24 = 2 ∗ 21 ∗ 21 ∗ 21 ∗ 20 = 2 ∗ 23 Na multiplicação de mesma base podemos somar os expoentes e manter a base (1+1+1+0 = 3) K - 1 Percebemos que o problema termina sempre que k = 0. Portanto, desta vez, a diminuição do nosso problema, ocorrerá no expoente e não no número que estamos somando.
  • 10.
    Um fato importantea se considerar sobre recursão - Nós podemos ter mais de um caso base! - Sempre precisamos encontrar uma maneira de diminuir o problema. O fator que vamos diminuir e qual é o nosso parâmetro de diminuição não será o mesmo para todos os problemas. Podemos, inclusive, ter que diminuir o problema utilizando mais que um parâmetro para isso. - É importante notar que o fator de diminuição nem sempre será em 1, pode por exemplo ser 2 ou até mesmo dividir o problema pela metade a cada passo recursivo!
  • 11.
    Mais um exemplo Sejao problema de elevar qualquer número n á um expoente qualquer k. Como resolver isso de maneira recursiva. Vamos ver algumas possíveis interações deste problema matemático, com n = 2 e k >= 0: 20 = 1 21 = 2 ∗ 20 22 = 2 ∗ 2 ∗ 20 = 2 ∗ 21 23 = 2 ∗ 2 ∗ 2 ∗ 20 = 2 ∗ 22 24 = 2 ∗ 21 ∗ 21 ∗ 21 ∗ 20 = 2 ∗ 23 Na multiplicação de mesma base podemos somar os expoentes e manter a base (1+1+1+0 = 3) K - 1 O caso base é fácil de perceber, pois quando k = 0, o problema terminou para todas as iterações. Logo k = 0 é o nosso caso base.
  • 12.
    Mais um exemplo Sejao problema de elevar qualquer número n á um expoente qualquer k. Como resolver isso de maneira recursiva. Vamos ver algumas possíveis interações deste problema matemático, com n = 2 e k >= 0: 20 = 1 21 = 2 ∗ 20 22 = 2 ∗ 2 ∗ 20 = 2 ∗ 21 23 = 2 ∗ 2 ∗ 2 ∗ 20 = 2 ∗ 22 24 = 2 ∗ 21 ∗ 21 ∗ 21 ∗ 20 = 2 ∗ 23 Na multiplicação de mesma base podemos somar os expoentes e manter a base (1+1+1+0 = 3) K - 1 Para o passo recursivo, percebemos que sempre podemos multiplicar n por uma potenciação de 𝑛 𝑘−1. O k-1 é em relação ao expoente inicial. Logo o passo recursivo: 𝑛 * 𝑛 𝑘−1
  • 13.
    Potenciação recursiva Nossa funçãoentão ficaria da seguinte forma: int pot(int n, int k){ if(k == 0) return 1; return n * pot(n,k-1); }
  • 14.
    Análise da recursividade Qualé a complexidade do algoritmo recursivo que calcula o fatorial de n? Como conseguimos calcular esse valor?
  • 15.
    Análise da recursividade Analisara complexidade de algoritmos recursivos não é tão simples assim e muitas vezes temos que utilizar recursos matemáticos mais aguçados para conseguir chegar à um valor.
  • 16.
    Análise da recursividade Analisara complexidade de algoritmos recursivos não é tão simples assim e muitas vezes temos que utilizar recursos matemáticos mais aguçados para conseguir chegar à um valor. Isto envolve saber a descrição matemática que nos dá o comportamento do algoritmo, que será definida como sua relação de recorrência! (recorrência, pois o algoritmo sempre “recorre” a si mesmo várias vezes para resolver um problema qualquer. Recorrência é o mesmo que repetição!)
  • 17.
    Relações de recorrência Umarelação de recorrência é sempre formada por: o caso base e por um elemento que se parece muito com o passo recursivo, mas tem a ver com número de operações completadas. Vamos tentar entender um pouco deste elemento, utilizando o fatorial recursivo de n.
  • 18.
    Relações de recorrência Sejauma relação de recorrência representada pelo símbolo 𝑇, podemos definir então a função de 𝑇(n), que será a função que descreverá nossa relação de recorrência, de modo que: 𝑇 𝑛 = 𝐶 , 𝑞𝑢𝑎𝑛𝑑𝑜 𝑛 𝑎𝑡𝑖𝑛𝑔𝑒 𝑜 𝑐𝑎𝑠𝑜 𝑏𝑎𝑠𝑒 𝑇 𝑛 𝑝𝑜𝑟 𝑎𝑙𝑔𝑢𝑚 𝑓𝑎𝑡𝑜𝑟 𝑑𝑒 𝑘 + 𝑑 𝑑 ≥< 0 Onde o valor mínimo de n depende do nosso problema matemático!
  • 19.
    Relações de recorrência Vamosutilizar como exemplo o fatorial de n. Sabemos que o caso base é quando n = 1 e neste caso, o valor retornado é 1. Logo C = 1 quando n = 1, então: 𝑇 𝑛 = 1 , 𝑠𝑒 𝑛 = 1
  • 20.
    Relações de recorrência Agoravamos analisar a função fatorial, para encontrar nossa relação de recorrência: int fatorial(int n){ if( n == 1 ) return 1; return n * fatorial(n-1); } Para encontrar a recorrência do algoritmo temos que nos atentar para o número de operações que temos a cada passo. Olhando para o passo recursivo, pode-se perceber que sempre vamos ter 1 multiplicação mais uma chamada da função fatorial com o nosso problema diminuído em 1. Portanto nossa recorrência pode ser definida por: 1 + 𝑇 𝑛 − 1 Onde T refere-se neste caso a função fatorial! Uma multiplicação e uma chamada de função com o problema diminuído em 1!
  • 21.
    Relações de recorrência Logo,k = 1, o fator de diminuição é uma subtração por k e d = 1, que é o valor de operações completadas por cada chamada da função. 𝑇 𝑛 = 1 , 𝑠𝑒 𝑛 = 1 𝑇 𝑛 − 1 + 1 ,
  • 22.
    Relações de recorrência Parafinalizar o nosso T(n), precisamos definir o valor mínimo que n atinge em que a recorrência ainda existe. Neste caso, é todo valor que n assume que é maior que o caso base. Logo 𝑇 𝑛 = 1 , 𝑠𝑒 𝑛 = 1 𝑇 𝑛 − 1 + 1 , 𝑝𝑎𝑟𝑎 𝑛 > 1 Quando n atingir 1, não teremos mais recorrências!
  • 23.
    Como resolver umarelação de recorrência? Temos duas maneiras de resolver uma relação de recorrência: - Por expansão dos fatores - Por indução matemática
  • 24.
    Resolvendo recorrências porexpansão de fatores. Receita de bolo! 1º) Copie a fórmula original 𝑇 𝑛 = 𝑇 𝑛 − 1 + 1 2º) Descubra por quanto que a recorrência é diminuída a cada passo (fator de diminuição k) T(n) está escrito em função de T(n-1) então a cada passo o parâmetro n é subtraído de 1 (k = 1)
  • 25.
    Resolvendo recorrências porexpansão de fatores. Receita de bolo! 3º) Encontre o valor de T para os próximos valores da diminuição, utilizando valor da equação original T(n) = T(n – 1) + 1 Como já sabemos que o fator de diminuição é subtraído de 1, então devemos achar os valores de T(n-1), T(n-2), T(n-3) e assim por diante, substituindo n pelos respectivos valores na equação inicial.
  • 26.
    Resolvendo recorrências porexpansão de fatores. Receita de bolo! 3º) Encontre o valor de T para os próximos valores da diminuição, utilizando valor da equação original T(n) = T(n – 1) + 1 Se ainda está confuso o que devemos fazer, pense nesse problema matemático, seja: 𝑓 𝑥 = 2𝑥 Se queremos saber o valor de f(2) e f(3) logo x = 2, x = 3, então fazemos: 𝑓 2 = 2 ∗ 2 = 4 𝑓 3 = 2 ∗ 3 = 6
  • 27.
    Resolvendo recorrências porexpansão de fatores. Receita de bolo! 3º) Encontre o valor de T para os próximos valores da diminuição, utilizando valor da equação original T(n) = T(n – 1) + 1 Portanto se queremos saber os valores de T(n-1), T(n-2)... Então n = n-1, n = n-2,... E fazemos como anteriormente substituindo os valores de n. Logo: 𝑇 (𝑛 − 1) = 𝑇 𝑛 − 1 − 1 + 1 = T n − 2 + 1 (3.1) 𝑇 (𝑛 − 2) = 𝑇 𝑛 − 2 − 1 + 1 = T n − 3 + 1(3.2) 𝑇 (𝑛 − 3) = 𝑇 𝑛 − 3 − 1 + 1 = T n − 4 + 1(3.3)
  • 28.
    Resolvendo recorrências porexpansão de fatores. Receita de bolo! 4º) Substitua os valores encontrados em 3, na equação original (chamamos isto de expansão da recorrência) T(n) = T(n-1) + 1 Utilizando 3.1, onde encontramos o valor de T(n-1): 𝑇 𝑛 = 𝑇 𝑛 − 2 + 1 + 1 ⇒ 𝑇 𝑛 = 𝑇 𝑛 − 2 + 2 (4.1) Utilizando 3.2, onde encontramos o valor de T(n-2), substituímos em 4.1 𝑇 𝑛 = 𝑇 𝑛 − 3 + 1 + 2 ⇒ 𝑇 𝑛 = 𝑇 𝑛 − 3 + 3 (4.2) k k
  • 29.
    Resolvendo recorrências porexpansão de fatores. Receita de bolo! 4º) Continuamos a substituir, até conseguirmos enxergar um padrão nas expansões: Utilizando 3.2, onde encontramos o valor de T(n-3), substituímos em 4.2: 𝑇 𝑛 = 𝑇 𝑛 − 4 + 1 + 3 ⇒ 𝑇 𝑛 = 𝑇 𝑛 − 4 + 4 (4.3) Podemos notar que o valor de k incrementa a cada expansão, que é o comportamento experado, já que estamos sempre diminuindo a recorrência pelo fator de 1 (valor inicial de k). A ideia é perceber o comportamento da recorrência ao se aumentar o valor de k (diminuir a recorrência)! k
  • 30.
    Resolvendo recorrências porexpansão de fatores. Receita de bolo! 4º) Analisando todas as iterações: 𝑇 𝑛 = 𝑇 𝑛 − 2 + 2 (4.1) 𝑇 𝑛 = 𝑇 𝑛 − 3 + 3 4.2 𝑇 𝑛 = 𝑇 𝑛 − 4 + 4 4.3 k A cada expansão da recorrência, k assume um novo valor. Percebemos também que o valor constante que é somado a recorrência e indica a quantidade de multiplicações que teremos que realizar para encontrar a solução do problema (fatorial de n) é o mesmo valor de k em todas as iterações.
  • 31.
    Resolvendo recorrências porexpansão de fatores. Receita de bolo! 4º) Analisando todas as iterações: 𝑇 𝑛 = 𝑇 𝑛 − 2 + 2 (4.1) 𝑇 𝑛 = 𝑇 𝑛 − 3 + 3 4.2 𝑇 𝑛 = 𝑇 𝑛 − 4 + 4 4.3 k Logo, depois de k expansões teremos: 𝑇 𝑛 = 𝑇 𝑛 − 𝑘 + 𝑘
  • 32.
    Resolvendo recorrências porexpansão de fatores. Receita de bolo! 5º) Encontrar quando a expansão para. Precisamos pensar no caso base, que é o mesmo que pensar em quando T(n-k) nos retornará um valor. Olhando para o caso base, sabemos que teremos um valor de retorno e não uma nova recorrência quando n = 1. Para o nosso caso, n = (n-k) que é o valor de argumento da recorrência [T(n-k)] 𝑇 𝑛 = 𝑇 𝑛 − 𝑘 + 𝑘 (5.1) Logo precisamos saber quando n-k = 1, pois então teremos T(1) e já sabemos que isso é igual a 1. 𝑛 − 𝑘 = 1 ⇒ 𝑘 = 𝑛 − 1
  • 33.
    Resolvendo recorrências porexpansão de fatores. Receita de bolo! 5º) Substituindo o valor de k encontrado (n-1) em 5.1 temos 𝑇 𝑛 = 𝑇 𝑛 − (𝑛 − 1) + 𝑛 − 1 = 𝑇 1 + 𝑛 − 1 Como sabemos que T(1) = 1, então 𝑇 𝑛 = 1 + 𝑛 − 1 𝑇 𝑛 = 𝑛
  • 34.
    Resolvendo recorrências porexpansão de fatores. Receita de bolo! 6º) Definir o limite assintótico de T(n) Como encontramos que T(n) = n, então neste caso sabemos que o algoritmo fatorial de n recursivo é O(n), maior grau no polinômio encontrado. Na prática, depois de várias décadas de estudo, sabe-se que o resultado da relação de recorrência é suficiente para conhecer a complexidade do algoritmo, porém se quisermos realmente provar (e às vezes isso será necessário!), precisamos utilizar indução matemática, que é um método da matemática discreta que nos ensina como provar problemas matemáticos, entre eles relações de recorrência.
  • 35.
    Resolvendo recorrências porexpansão de fatores. Receita de bolo! 6º) Definir o limite assintótico de T(n) Como encontramos que T(n) = n, então neste caso sabemos que o algoritmo fatorial de n recursivo é O(n), maior grau no polinômio encontrado. Na prática, depois de várias décadas de estudo, sabe-se que o resultado da relação de recorrência é suficiente para conhecer a complexidade do algoritmo, porém se quisermos realmente provar (e às vezes isso será necessário!), precisamos utilizar indução matemática, que é um método da matemática discreta que nos ensina como provar problemas matemáticos, entre eles relações de recorrência.
  • 36.
    Indução matemática Em umalinguagem bem simplificada. Você pode usar a indução matemática para provar uma expressão matemática quando: 1 – Sabe que ela é verdadeira para algum valor. 2 – Quer provar que ela é válida então para esse valor em relação a um fator de um (pode ser aumentar ou diminuir). Ou seja, quer provar que o próximo valor e os próximos valores depois deste também são verdadeiros.
  • 37.
    Indução matemática Características: 1 –O passo 1 do slide anterior é chamado de passo base. 2 – O passo 2 é o passo indutivo.
  • 38.
    Indução matemática Exemplo. Sejaum teorema que tenha como parâmetro um número natural n. Provando que T é válido para todos os valores de n, provamos que: 1 – T é válido para n = 1 (eu tenho que saber que isto é verdade!); 2 – Para todo n > 1, se T é válido para n – 1, então T é válido para n (Se conseguirmos provar que n – 1 é válido (e isto implica em provar que n – 2, n – 3 e assim por diante também é válido), então podemos provar que n é verdadeiro. Esse é o passo indutivo.
  • 39.
    O que éuma prova? Em matemática, uma prova é uma argumentação precisa que procura convencer o leitor de que uma certa preposição, previamente enunciada está correta. Num sentindo mais informa, uma prova é um texto que ajuda o leitor a entender por que uma dada afirmação é verdadeira!
  • 40.
    Provando uma relaçãode recorrência por indução matemática Primeiro temos que provar que o passo base é verdadeiro. Para nossa equação de recorrência do problema do fatorial: 𝑇 𝑛 = 1 , 𝑠𝑒 𝑛 = 1 𝑇 𝑛 − 1 + 1 , 𝑝𝑎𝑟𝑎 𝑛 > 1 Logo primeiro queremos provar que T(1) = 1. Sabemos que T(1) é verdadeiro, pois quando n = 1, o algoritmo não realiza nenhuma multiplicação. Logo, o nosso caso base é verdadeiro!
  • 41.
    Provando uma relaçãode recorrência por indução matemática Agora supomos que T(k) = k (pois não sabemos quanto é realmente este valor antes de calcular todas as multiplicações. A variável n foi substituída por k, pois estamos generalizando para quaisquer valores n > 1, pois quando n = 1 já provamos ser verdadeiro). Para provar que T(k) = k é verdadeiro, precisamos provar que T(k + 1) = k + 1 também é verdadeiro. Se conseguirmos provar que T(k + 1) é verdadeiro, então T(k) também será verdadeiro, pois derivamos T(k+1) de T(k) e assim nosso passo indutivo seria verdadeiro e nossa relação de recorrência também.
  • 42.
    Provando uma relaçãode recorrência por indução matemática A ideia principal aqui é a seguinte. Vamos encontrar definir nossa hipótese de indução. A hipótese de indução é sempre nosso passo recursivo: 𝑇 𝑛 = 𝑇 𝑛 − 1 + 1 Vamos a partir da nossa hipótese de indução, determinar o valor de T(k + 1).
  • 43.
    Provando uma relaçãode recorrência por indução matemática 𝑇 𝑘 + 1 = 𝑇 (𝑘 + 1) − 1 + 1 = 𝑇 𝑘 + 1 Sempre, que queremos provar T(k+1), precisamos tentar deixá-lo em função de T(k), que é o valor que supomos no começo do exercício que queríamos provar. Supomos que T(k) = k, então vamos substituí-lo na expressão encontrada acima.
  • 44.
    Provando uma relaçãode recorrência por indução matemática Como supomos que T(k) = k no começo do exercícios, podemos então substituí-lo na expressão encontrada no slide anterior: 𝑇 𝑘 + 1 = 𝑇 𝑘 + 1 T(k + 1) = 𝑘 + 1 Note que é exatamente o que queríamos provar, pois lembre-se que no começo do exercício, supomos T(k) = k e queríamos provar que T(k+1) = k +1.
  • 45.
    Provando uma relaçãode recorrência por indução matemática Escrever uma prova de indução matemática sempre envolve: - Provar o caso base - Supor T(k) = k e tentar provar que T(k+1) = k+1 - Encontrar uma hipótese de indução, que é o nosso passo recursivo - Utilizar a hipótese de indução para encontrar T(k+1) em função de T(k) - Manipular T(k+1) para que ele seja k+1