Recursão e Big O
-
03-07-2019 - |
Pergunta
Eu tenho trabalhado através de um recente trabalho de casa Ciência da Computação envolvendo recursão e notação big-O. Eu acredito que eu entendo isso muito bem (certamente não perfeitamente, embora!) Mas há uma questão em particular que está me dando mais problemas. O curioso é que, olhando-o, parece ser a simples mais sobre o trabalho de casa.
Fornecer a melhor taxa de crescimento usando a notação big-Oh para a solução para o seguinte recorrência?
T (1) = 2
T (n) = 2T (n - 1) + 1 para n> 1
E as opções são:
- O (N log N)
- O (n ^ 2)
- O (2 ^ n)
- O (n ^ n)
Eu entendo que as obras grandes O como um limite superior, para descrever a maior quantidade de cálculos, ou o maior tempo de execução, esse programa ou processo vai demorar. Eu sinto que esta recursão especial deve ser O (n), uma vez que, no máximo, a recursão ocorre apenas uma vez para cada valor de n. Desde que n não está disponível, ou é melhor do que isso, O (nlogn), ou pior, sendo as outras três opções.
Então, minha pergunta é: Por que não é este o (n)
Solução
Há um par de maneiras diferentes para resolver recorrências: substituição, árvore de recorrência e teorema de mestre. Teorema Mestre não irá funcionar no caso, porque ele não se encaixa no formulário mestre teorema.
Você pode usar os outros dois métodos, mas a maneira mais fácil para este problema é resolvê-lo de forma iterativa.
T (n) = 2T (n-1) + 1 | T (n) = 4T (n-2) + 2 + 1 | T (n) = T8 (n-3) + 4 + 2 + 1 | T (n) = ...
Veja o padrão?
T (n) = 2 n-1 ·T (1) + 2 n-2 + 2 n-3 +. .. + 1 |
T (n) = 2 n-1 ·2 + 2 n-2 + 2 n-3 + ... + 1
T (n) = 2 n + 2 n-2 + 2 n-3 + ... + 1
Portanto, o mais apertada ligado é T (2 n ).
Outras dicas
Eu acho que você ter entendido mal a pergunta um pouco. Não pedir-lhe quanto tempo que seria necessário para resolver a recorrência. Ele está pedindo o que o big-O (a assintótica ligado) da própria solução é.
O que você tem a fazer é chegar a uma solução fechada, i. e. a fórmula não-recursiva para T (n), e, em seguida, determinar o que o grande-O de expressão que é.
A questão está pedindo a notação big-Oh para a solução para a recorrência, e não o custo do cálculo da recorrência.
Dito de outra forma: a recorrência produz:
1 -> 2
2 -> 5
3 -> 11
4 -> 23
5 -> 47
O big-Oh notação melhor descreve a sequência 2, 5, 11, 23, 47, ...
A maneira correta de resolver isso é para resolver as equações de recorrência.
Eu acho que isso vai ser exponencial. Cada incremento de n faz com que o valor a ser duas vezes maior.
T(2) = 2 * T(1) = 4
T(3) = 2 * T(2) = 2 * 4
...
T (x) seria o tempo de execução do seguinte programa (por exemplo):
def fn(x):
if (x == 1):
return # a constant time
# do the calculation for n - 1 twice
fn(x - 1)
fn(x - 1)
Eu acho que isso vai ser exponencial. Cada incremento de n traz o dobro de cálculo.
Não, isso não acontece. Muito pelo contrário:
Considere que para tempo n iterações, ficamos correndo R . Então, para n + 1 iterações vamos obter exatamente R + 1.
Assim, a taxa de crescimento é constante e o tempo total de funcionamento é, de facto O (
No entanto, acho que a suposição de Dima sobre a questão é certa embora sua solução é excessivamente complicado:
O que você tem a fazer é chegar a uma solução fechada, i. e. a fórmula não-recursiva para T (n), e, em seguida, determinar o que o grande-O de expressão que é.
É suficiente para examinar o tamanho relativo de T (
Em primeiro lugar, todas as quatro respostas são piores do que O (n) ... O (n * log n) é mais complexa do que O velho liso (n). Qual é maior: 8 ou 8 * 3, 16 ou 16 * 4, etc ...
Por que a questão real. A solução geral pode, obviamente, ser resolvido em tempo constante, se você não está fazendo a recursão
(T (n) = 2 ^ (n - 1) + 2 ^ (n) - 1), de modo que não é o que eles estão pedindo
.E como você pode ver, se escrever o código recursivo:
int T( int N )
{
if (N == 1) return 2;
return( 2*T(N-1) + 1);
}
É óbvio que é O (n).
Assim, parece ser uma pergunta mal formulada, e eles provavelmente estão pedindo o crescimento da função em si, não a complexidade do código. Isso é 2 ^ n. Agora vá fazer o resto da sua casa ... e estudar-se sobre O (n * log n)
Calculando uma solução fechada para a recursividade é fácil. Por inspeção, você acho que a solução é
T(n) = 3*2^(n-1) - 1
Então você provar por indução que este é verdadeiramente uma solução. caso Base:
T(1) = 3*2^0 - 1 = 3 - 1 = 2. OK.
Indução:
Suppose T(n) = 3*2^(n-1) - 1. Then T(n+1) = 2*T(n) + 1 = 3*2^n - 2 + 1 = 3*2^((n+1)-1) - 1. OK.
onde a primeira igualdade decorre da definição de recorrência, e o segundo a partir da hipótese indutiva. QED.
3 * 2 ^ (n-1) -. 1 é claramente teta (2 ^ n), por conseguinte, a resposta à direita é a terceira
Para as pessoas que responderam O (n): Eu não poderia concordar mais com Dima. O problema faz não pedir mais apertados limite superior para a complexidade computacional de um algoritmo para calcular T (n) (o que seria agora O (1), desde a sua forma fechada foi fornecido). O problema pede mais apertados limite superior em T (n) em si , e que é o exponencial.