Qual a complexidade temporal desta função?

7

Este é um exemplo em minhas anotações de aula. Esta função possui complexidade de tempoO(nlogn)? Como o pior caso é a função entra em elseramificação e 2 loops aninhados com complexidade de tempo delogn e n, então é O(nlogn). Estou certo?

int j = 3;
int k = j * n / 345;
if(k > 100){
    System.out.println("k: " + k);
}else{
    for(int i=1; i<n; i*=2){
        for(int j=0; j<i; j++){
            k++;
        }
    }
}
Eterno
fonte

Respostas:

5

A complexidade temporal do algoritmo mencionado é O(1), por causa de K>100 você tem uma operação constante (println) e sabe: j=3,k=3n/345100=3n/345n=11500, meios para n11500 seu algoritmo tem um tempo de execução constante (também outra parte é constante, porque apenas para n<11500 será chamado).

Por ser mais claro, dê uma olhada nesta questão.

Comunidade
fonte
talvez apenas para completar sua resposta, você deve mencionar que, ao falar sobre complexidade de tempo, apenas nos preocupamos com o que acontece quando n. Ou você pode vincular a uma das perguntas que lidam com complexidades, como esta:
Ran G.
@Tocou. Você está absolutamente certo, na verdade, pensei em escrever uma definição formal de Big-Oh, mas achei que todo mundo sabia disso, na verdade, como você é o suficiente para encontrarn0 0 para valor inicial, c0 0para coeficiente constante. Eu determinein0 0, mas eu não mencionei c0 0(parece claro), mas sim, eu irei vinculá-lo à resposta de Raphael (com toda a preguiça de escrever).
4

EDIT: Como apontado por Saeed Amiri, este é realmente O(1 1), já que para grandes assintoticamente grandes n, o elseramo não é realmente ocupado; a ifpeça é executada, que é um tempo trivialmente constante. O restante desta resposta, que deixo para referência, estaria correto se, por exemplo, a condição fosse k < 100. Desculpe pela confusão.

A complexidade do tempo será essencialmente da ordem do número de vezes que ké incrementado no forloop aninhado . Há algumas coisas extras acontecendo, mas se você pensar sobre isso, é só brincar com fatores constantes. Quantas vezesk ser incrementado?

Quando Eu=1 1, ké incrementado uma vez. QuandoEu=2, ké incrementado duas vezes adicionais. QuandoEu=x, k é incrementado xtempos adicionais. Vamos agora assumir quen=2m+1 1. Então a última iteração do loop interno fará com kque seja incrementada2m vezes.

k é incrementado um total geral de 1 1+2+...+2m vezes ou 2(m+1)1vezes. Lembre-se de que `n=2m+1. assimn1=2me nós temos isso k é incrementado 2(n1)1 1 vezes no total.

k é incrementado um número de vezes linear em n; então isso é tudoO(n).

Patrick87
fonte
-1 A complexidade do tempo é independente do loop for. (Veja minha resposta e tente você mesmo).
11
@SaeedAmiri Opa, você está certo. Eu meio que aprimorei a elseparte sem verificar as condições prévias. Edição de resposta para refletir isso.
Patrick87
Sim, agora sua resposta está correta.
1

Embora os comentários sobre os ramos if / else estejam todos corretos, eu diria que a resposta é O (log n). A razão é que

System.out.println("k: " + k);

envolve a conversão de um número inteiro em saída de string, e este será O (log n) no caso geral (apenas para imprimir cada dígito, mesmo que uma tabela de pesquisa tenha sido usada).

Não tenho certeza se isso foi uma parte complicada da pergunta ou não ...

ex0du5
fonte
0

Vamos ver:

int j = 3; leva tempo constante O (1).

int k = j * n / 345toma alguma função de tempo do logaritmo das variáveis j e n

if (k > 100) leva tempo constante O (1).

System.out.println("k: " + k);assume a função de tempo do logaritmo de k

for (int i=1; i<n; i*=2)toma a função de tempo do logaritmo de n , Θ (log (n)) para ser exata, porque se t é o número de iterações desse loop for, o valor de i pode ser expresso como: i = 2 t-1 , se t = 1 na primeira iteração, para que o loop continue enquanto 2 t-1 <n , onde n não está sendo alterado.

No cálculo, se 2 t-1 <n então t-1 <log 2 (n)

E se t-1 <log 2 (n) então t <log 2 (n) +1

E se em cada iteração, t é incrementado em 1, podemos ver que esse loop for realmente leva Θ (log (n)), se a complexidade do tempo de execução do código dentro do loop for for constante, ou seja, O (1) claro!

Dentro deste loop for, existe outro loop for:

for (int j=0; j<i; j++) k++;

Vamos analisar isso:

k++; leva tempo constante, ou seja, tempo O (1).

Portanto, é interessante analisar a complexidade do tempo de execução do loop for interno.

Vamos ver:

De acordo com o código desse loop for interno, parece que existem i iterações nesse loop for interno, portanto, o tempo de execução é Θ (i) , não apenas O (i) , porque não quebra no meio, mas lembre-se de que i <n , por causa do loop for externo, portanto, embora no início seja necessário 1 iteração quando i = 1 , 2 iterações quando i = 2 , 4 iterações quando i = 4 , 8 iterações quando i = 4 , 8 iterações quando i = 8 . .. e etc, porque eu dobra-se no final do loop for externo na linha i * = 2 , portanto, no total, a execução é 1 + 2 + 4 + 8 + ... iterações, mas até i≥nportanto, o número máximo possível de iterações nesse loop for interno é quando i = n-1 em termos de pior caso; portanto, na última execução do loop for interno, ele executou n-1 iterações, portanto, antes de executar ( n-1) / 2 iterações e antes da execução (n-1) / 4 iterações e antes da execução (n-1) / 8 iterações ... portanto, no total, a execução foi:

n-1 + (n-1) / 2 + (n-1) / 4 + (n-1) / 8 ... = (n-1) (1 + 1/2 + 1/4 + 1/8 ...) = (n-1) (2) = 2n-2 = Θ (n)

Lembre-se de que 1 + 1/2 + 1/4 + 1/8 ... = 2 é uma soma bem conhecida da sequência geométrica.

Lembre-se de que o loop for externo leva Θ (log (n))

E o loop for interno leva Θ (n).

E a complexidade do tempo de execução do loop for interno para o loop é a complexidade do tempo de execução do loop for externo multiplicada pela complexidade do tempo de execução do loop for interno, portanto, leva Θ (nlogn) o tempo de execução.

Portanto, em resumo, o tempo de execução dessa função é Θ (nlogn) .

Espero que isso responda bem à sua pergunta e ensine bem como analisar a complexidade do tempo de execução de algoritmos e funções.

Troca de despedida
fonte
Por que minha resposta foi rapidamente rejeitada?
Farewell Stack Exchange
Minha análise está errada?
Troca de pilha de despedida
"int k = j * n / 345 leva alguma função de tempo do logaritmo das variáveis ​​j e n". Você está usando o custo de tempo logarítmico por operação em números, mas geralmente o custo de tempo constante por operação é usado, como também foi planejado pela pergunta. Além disso, sua análise dos 2 loops está errada, pois j é executado até i no loop interno. O (n), como mencionado por outra pessoa, está correto.
Albert Hendriks
Ok, eu concordo com você.
Farewell Stack Exchange