Determinare se un algoritmo è O (log n)


25

Sto aggiornando la mia teoria CS e voglio sapere come identificare la complessità di un algoritmo O (log n). In particolare, esiste un modo semplice per identificarlo?

So che con O (n), di solito hai un singolo ciclo; O (n ^ 2) è un doppio loop; O (n ^ 3) è un triplo loop, ecc. Che ne dici di O (log n)?



Ah, è l'unico posto in cui non ho cercato :)
Atif,

Risposte:


32

So che con O (n), di solito hai un singolo ciclo; O (n ^ 2) è un doppio loop; O (n ^ 3) è un triplo loop, ecc. Che ne dici di O (log n)?

Ci stai davvero andando nel modo sbagliato qui. Stai cercando di memorizzare quale espressione di big-O si accompagna a una determinata struttura algoritmica, ma dovresti davvero contare il numero di operazioni richieste dall'algoritmo e confrontarlo con la dimensione dell'input. Un algoritmo che scorre su tutto il suo input ha prestazioni O (n) perché esegue il loop n volte, non perché ha un singolo loop. Ecco un singolo loop con prestazioni O (log n):

for (i = 0; i < log2(input.count); i++) {
    doSomething(...);
}

Pertanto, qualsiasi algoritmo in cui il numero di operazioni richieste è nell'ordine del logaritmo della dimensione dell'input è O (log n). La cosa importante che l'analisi big-O ti dice è come cambia il tempo di esecuzione di un algoritmo rispetto alla dimensione dell'input: se raddoppi la dimensione dell'input, l'algoritmo compie 1 ulteriore passo (O (log n)) , il doppio di passi (O (n)), il doppio di passi (O (n ^ 2)), ecc.

Aiuta a sapere per esperienza che gli algoritmi che partizionano ripetutamente i loro input in genere hanno "log n" come componente delle loro prestazioni? Sicuro. Ma non cercare il partizionamento e saltare alla conclusione che le prestazioni dell'algoritmo sono O (log n) - potrebbe essere qualcosa come O (n log n), che è piuttosto diverso.


3
Si noti che un modo più colloquiale per dire "sull'ordine del logaritmo della dimensione" è quello di dire "sull'ordine del numero di cifre nella dimensione".

@Caleb la base effettiva del logaritmo non è importante quando si parla di ridimensionamento.

Parlare di assoluti di @Caleb non ha senso con big-O. Una formulazione che potrebbe piacerti di più: quando il numero di cifre raddoppia, il numero di passaggi raddoppia.

Parlare di assoluti di @Caleb non ha senso con big-O. Una formulazione che potrebbe piacerti di più: quando il numero di cifre raddoppia, il numero di passaggi raddoppia.

@ ThorbjørnRavnAndersen Sì, questo significa "il logaritmo della dimensione". Non sono sicuro di quale sia il tuo problema con la frase, tranne per il fatto che avresti scelto di dirlo in modo diverso. Fondamentalmente, penso che siamo d'accordo.
Caleb,

25

L'idea è che un algoritmo è O(log n)se invece di scorrere una struttura 1 per 1, dividi la struttura a metà più e più volte e fai un numero costante di operazioni per ogni divisione. Gli algoritmi di ricerca in cui lo spazio di risposta continua a dividere sono O(log n). Un esempio di questo è la ricerca binaria , in cui si continua a dividere un array ordinato a metà più e più volte fino a trovare il numero.

Nota: non devi necessariamente dividere a metà.


1
Cosa succede se divido l'input in due e quindi ripeto 2 ^ (n / 2) volte sul resto prima di dividerlo di nuovo? (Naturalmente so cosa, allora, volevo solo mostrare un esempio in cui questo approccio semplicistico fallisce).
Tamás Szelei,

@afish È un po 'raro. È straordinariamente raro durante la ricerca.
Donal Fellows il

1
La teoria dell'algoritmo di @DonalFellows non è una scienza empirica. E la domanda non riguardava la ricerca, è solo che la menzione di log ninnescati riflessi di ricerca binaria nelle persone.
Tamás Szelei,

2
Il partizionamento non rende l'algoritmo O (log n), ma (di solito) aggiunge un fattore di log n al limite big-O. Specie ricorsive come heapsort e mergesort sono esempi perfetti: partizionano l'input, ma poi partizionano ricorsivamente entrambe le partizioni risultanti. Il risultato è la prestazione O (n log n).
Caleb,

@afish: buon punto. Il mio obiettivo con questa risposta è di renderlo il più semplice possibile data la natura della domanda. Ho cambiato la linea "dividi la struttura a metà ..." in "dividi la struttura a metà ... e fai un numero costante di operazioni per ogni divisione" per cercare di ottenere questo punto semplicemente.
Casey Patton,

2

Gli esempi tipici sono quelli che si occupano della ricerca binaria. Ad esempio, di solito è un algoritmo di ricerca binariaO(log n) .

Se hai un albero di ricerca binario , la ricerca, l'inserimento e l'eliminazione sono tutti O(log n)complessi.

Ogni situazione in cui si suddivide continuamente lo spazio coinvolgerà spesso un log ncomponente. Questo è il motivo per cui molti algoritmi di ordinamento hanno O(nlog n)complessità, perché spesso partizionano un set e ordinano mentre vanno.


1

Se lo vuoi semplice come "single loop -> O (n), double loop -> O (n ^ 2)", allora la risposta è probabilmente "Tree -> O (log n)". Attraversare più accuratamente un albero dalla radice a una foglia (non tutte!) O viceversa. Tuttavia, queste sono tutte semplificazioni eccessive.


Quindi, cosa c'è di sbagliato nella mia risposta? Sono aperto a critiche costruttive.
scarfridge il

0

Volete sapere se esiste un modo semplice per identificare se un algoritmo è O (log N).

Bene: corri e cronometra. Eseguilo per input 1.000, 10.000, 100.000 e un milione.

Se vedi un tempo di esecuzione di 3,4,5,6 secondi (o alcuni multipli) puoi tranquillamente dire che è O (log N). Se è più simile: 1,10,100,1000 secondi, probabilmente è O (N). E se è come 3,40,500,6000 secondi, allora è O (N log N).


Tutti dovrebbero dare a questa risposta un
voto positivo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.