Come si fa a sapere quale notazione dell'analisi della complessità del tempo usare?


90

Nella maggior parte delle lezioni introduttive sugli algoritmi, vengono introdotte notazioni come O (Big O) e Θ , e uno studente in genere imparerebbe ad usare una di queste per trovare la complessità temporale.

Tuttavia, ci sono altre notazioni, come o , Ω e ω . Esistono scenari specifici in cui una notazione sarebbe preferibile a un'altra?


2
non è tanto preferibile quanto applicabile ...
vzn

Risposte:


76

Ti riferisci alla notazione Landau . Non sono simboli diversi per la stessa cosa ma hanno significati completamente diversi. Quale è "preferibile" dipende interamente dall'affermazione desiderata.

significa che f cresce al più velocemente di g , asintoticamente e fino a un fattore costante; pensalo come un . f o ( g ) è la forma più rigorosa, cioè < .fO(g)fgfo(g)<

ha il significato simmetrico:cresce almeno quanto. è suo cugino più severo. Puoi vedere cheè equivalente a.fΩ(g)g ω f Ω ( g ) g O ( f )fgωfΩ(g)gO(f)

f g f O ( g ) Ω ( g ) f g Θ OfΘ(g) significa che cresce circa quanto ; formalmente . (uguaglianza asintotica) è la sua forma più forte. Spesso intendiamo quando usiamo .fgfO(g)Ω(g)f~gΘO

Nota come e i suoi fratelli sono classi di funzioni . È importante essere molto consapevoli di questo e delle loro definizioni precise - che possono differire a seconda di chi sta parlando - quando si fa "aritmetica" con loro.O(g)

Quando provi le cose, abbi cura di lavorare con la tua definizione precisa. Ci sono molte definizioni per i simboli Landau in giro (tutte con la stessa intuizione di base), alcune delle quali sono equivalenti su alcuni insiemi di funzioni ma non su altri.

Letture consigliate:

Se sei interessato a usare la notazione Landau in modo rigoroso e solido, potresti essere interessato ai recenti lavori di Rutanen et al. [1]. Formulano criteri necessari e sufficienti per la notazione asintotica quando li usiamo in algoritmi, mostrano che la definizione comune non riesce a soddisfarli e forniscono una definizione (in effetti) praticabile.


  1. Una definizione generale della notazione O per l'analisi dell'algoritmo di K. Rutanen et al. (2015)

5
Voglio solo sottolineare che sebbene agisca come e Ω agisca come , ci sono differenze; non è difficile trovare le funzioni g ed f tale che f O ( g ) ed f Ohm ( g ) . OΩgffO(g)fΩ(g)
Zach Langley

1
+1 per la menzione delle classi di funzioni. Cose come e Ω ( 2 n ) appaiono ovunque in documenti e libri, il che può essere fonte di confusione per le persone che affrontano queste notazioni per la prima volta. o(1)Ω(2n)
Janoma

7
@ZachLangley Quello che dici è molto vero. Non esiste un ordine totale qui. Probabilmente è pericoloso far apparire affatto, ma penso che serva allo scopo della costruzione dell'intuizione.
Raffaello

42

Big O: limite superiore

"Big O" ( ) è di gran lunga il più comune. Quando si analizza la complessità di un algoritmo, la maggior parte delle volte, ciò che conta è avere un limite superiore alla velocità con cui il tempo di esecuzione¹ aumenta quando aumenta la dimensione dell'input. Fondamentalmente vogliamo sapere che l'esecuzione dell'algoritmo non richiederà "troppo tempo". Non possiamo esprimerlo in unità di tempo effettive (secondi), perché ciò dipenderebbe dall'implementazione precisa (il modo in cui è scritto il programma, quanto è buono il compilatore, quanto è veloce il processore della macchina, ...). Quindi valutiamo ciò che non dipende da tali dettagli, ovvero quanto tempo ci vuole per eseguire l'algoritmo quando gli forniamo input più grandi. E ci preoccupiamo soprattutto quando possiamo essere sicuri che il programma sia stato completato, quindi di solito vogliamo sapere che ci vorrà un tale tempo o meno.O

Dire che un algoritmo ha un tempo di esecuzione di per una dimensione di input n significa che esiste una costante K tale che l'algoritmo completa al massimo KO(f(n))nK passi, ovvero il tempo di esecuzione dell'algoritmo cresce al più velocemente di f (fino a un fattore di ridimensionamento). Notando T ( n ) il tempo di esecuzione dell'algoritmo per la dimensione di input n , O ( n ) significa informalmente che T ( n ) f ( n ) fino ad un fattore di ridimensionamento.Kf(n)fT(n)nO(n)T(n)f(n)

Limite inferiore

A volte, è utile avere più informazioni di un limite superiore. è il contrario di O : esprime che una funzione cresce almeno altrettanto velocemente di un'altra. T ( n ) = Ω ( g ( n ) ) significa che T ( N ) K g ( n ) per una costante K , o per dirla in modo informale, T ( n ) g ( n ) fino ad un certo ridimensionamento fattore.ΩOT(n)=Ω(g(n))T(N)K'g(n)K'T(n)g(n)

Quando il tempo di esecuzione dell'algoritmo può essere determinato con precisione, combina O e Ω : esprime che è noto il tasso di crescita di una funzione, fino a un fattore di ridimensionamento. T ( n ) = Θ ( h ( n ) ) significa che K h ( n ) T ( n ) K h ( n ) per alcune costanti K e K . Informalmente parlando, T (ΘOΩT(n)=Θ(h(n))Kh(n)T(n)K'h(n)KK' fino ad un certo fattore di scala.T(n)h(n)

Ulteriori considerazioni

I "piccoli" e ω sono usati molto meno spesso nell'analisi della complessità. La piccola o è più forte della grande O ; dove O indica una crescita che non è più veloce, o indica che la crescita è strettamente più lenta. Al contrario, ω indica una crescita strettamente più rapida.oωoOOoω

Sono stato leggermente informale nella discussione sopra. Wikipedia ha tutte le definizioni e un approccio più matematico.

Tieni presente che l'uso del segno uguale in e simili è un termine improprio. A rigor di termini, O ( f ( n ) ) è un insieme di funzioni della variabile n , e dovremmo scrivere T O ( f ) .T(n)=O(f(n))O(f(n))nTO(f)

Esempio: alcuni algoritmi di ordinamento

Dato che è piuttosto secco, lasciami fare un esempio. La maggior parte degli algoritmi di ordinamento ha un tempo di esecuzione quadratico nel caso peggiore, ovvero per un input di dimensione , il tempo di esecuzione dell'algoritmo è O ( n 2 ) . Ad esempio, l' ordinamento di selezione ha un tempo di esecuzione O ( n 2 ) , poiché la selezione dell'elemento k th richiede confronti n - k , per un totale di n ( n - 1 ) / 2 confronti. In effetti, il numero di confronti è sempre esattamente n ( n -nO(n2)O(n2)Kn-Kn(n-1)/2 , che cresce come n 2 . Quindi possiamo essere più precisi sulla complessità temporale dell'ordinamento per selezione: è Θ ( n 2 ) .n(n-1)/2n2Θ(n2)

Ora prendi il tipo di unione . Unisci ordinamento è anche quadratico ( ). Questo è vero, ma non molto preciso. Unisci ordinamento infatti ha un tempo di esecuzione di O ( nO(n2) nel peggiore dei casi. Come per l'ordinamento di selezione, il flusso di lavoro dell'ordinamento di unione è essenzialmente indipendente dalla forma dell'input e il suo tempo di esecuzione è sempre nO(nlg(n)) fino a un fattore moltiplicativo costante, cioè è Θ ( nnlg(n) .Θ(nlg(n))

Quindi, considera quicksort . Quicksort è più complesso. È certamente . Inoltre, il caso peggiore di quicksort è quadratico: il caso peggiore è Θ ( n 2 ) . Tuttavia, il caso migliore di quicksort (quando l'ingresso è già ordinato) è lineare: il migliore che possiamo dire per un limite inferiore a quicksort in generale è Ω ( n ) . Non ripeterò qui la prova, ma la complessità media di quicksort (la media rilevata su tutte le possibili permutazioni dell'input) è Θ ( nO(n2)Θ(n2)Ω(n) .Θ(nlg(n))

Ci sono risultati generali sulla complessità degli algoritmi di ordinamento in impostazioni comuni. Supponiamo che un algoritmo di ordinamento possa confrontare solo due elementi alla volta, con un risultato sì o no (o oppure x > y ). Quindi è ovvio che il tempo di esecuzione di qualsiasi algoritmo di ordinamento è sempre Ω ( n ) (dove n è il numero di elementi da ordinare), perché l'algoritmo deve confrontare ogni elemento almeno una volta per sapere dove si adatterà. Questo limite inferiore può essere soddisfatto, ad esempio, se l'input è già ordinato e l'algoritmo confronta semplicemente ciascun elemento con quello successivo e li mantiene in ordine (ovvero n - 1XyX>yΩ(n)nn-1i confronti). Ciò che è meno ovvio è che il tempo di funzionamento massimo è necessariamente . È possibile che l'algoritmo a volte comporti un numero inferiore di confronti, ma deve esserci una costante K tale che per qualsiasi dimensione di input n , vi sia almeno un input su cui l'algoritmo effettua più di K n l g ( n ) confronti. L'idea della dimostrazione è costruire l'albero decisionale dell'algoritmo, cioè seguire le decisioni che l'algoritmo prende dal risultato di ogni confronto. Poiché ogni confronto restituisce un risultato sì o no, l'albero decisionale è un albero binario. Ci sono n !Ω(nlg(n))KnKnlg(n)n!possibili permutazioni dell'input e l'algoritmo deve distinguere tra tutti loro, quindi la dimensione dell'albero decisionale è . Poiché l'albero è un albero binario, richiede una profondità di Θ ( l g ( n ! ) ) = Θ ( nn! per adattarsi a tutti questi nodi. La profondità è il numero massimo di decisioni che l'algoritmo prende, quindi l'esecuzione dell'algoritmo comporta almeno questo numero di confronti: il tempo di esecuzione massimo è Ω ( nΘ(lg(n!))=Θ(nlg(n)) .Ω(nlg(n))

¹ O altro consumo di risorse come spazio di memoria. In questa risposta, prendo in considerazione solo il tempo di esecuzione.


1
"Tuttavia, il caso migliore di quicksort (quando l'ingresso è già ordinato) è lineare" questo è il caso peggiore !!
user5507

@ user5507: in realtà dipende dalla strategia pivot. Se il primo (o l'ultimo) elemento è scelto come perno, allora hai ragione; ma se scegli l'elemento centrale o la mediana del primo, medio, ultimo, l'input ordinato è il caso migliore.
Chirlu,

"I piccoli o e ω sono usati molto meno spesso nell'analisi della complessità." Questo non è vero nell'analisi della complessità dello spazio. Nell'analisi della complessità temporale, in genere si utilizzano o e ω quando si contano operazioni specifiche (confronti, ricerche su disco, errori nella cache, cosa si ha). Ma dato che puoi sempre aspettare e acquistare un computer più veloce, il "tempo della parete" è sempre "fino a un fattore costante", quindi big-O è molto più comune. Nell'analisi dello spazio, ci sono spesso limiti inferiori rigidi a causa della teoria dell'informazione, quindi è estremamente comune vedere dimensioni riportate come "f (n) + o (f (n)) bit" dove f (n) è il limite inferiore.
Pseudonimo del

Mentre ci penso: se f (n) è un limite inferiore teorico alla dimensione di una struttura di dati, uno che usa f (n) + O (1) (overhead costante) è chiamato "implicito", uno che usa f (n) + O (f (n)) (overhead relativo costante) è chiamato "compatto", e uno che usa f (n) + o (f (n)) (l'overhead relativo diventa infine insignificante) è chiamato "succinto ". Buoni termini per sapere se hai mai bisogno di lavorare in quello spazio.
Pseudonimo del

17

In genere viene utilizzato per indicare i limiti superiori (una stima dall'alto), mentre Ω viene utilizzato per indicare i limiti inferiori (una stima dal basso) e Θ viene utilizzato quando corrispondono, nel qual caso è possibile utilizzare Θ al posto di loro (di solito) per dichiarare il risultato.OΩΘΘ


3
"Tipicamente"? Possono essere usati per qualcos'altro?
svick

1
@svick, sì, ad es. che non è un'istruzione con limite superiore. Con un'istruzione di limite superiore intendo qualcosa di simile a f = O ( g ) che esprime un limite superiore su f . P=DTime(nO(1))f=O(g)f
Kaveh

4
In realtà, Kaveh, questa è un'affermazione superiore. La traduzione inglese propoer di " " è "P è l'insieme di problemi che possono essere risolti utilizzando AT MOST un numero polinomiale di operazioni". Se non volevi dire "al massimo", avresti dovuto scrivere P = D T i m e ( n Θ ( 1 ) ) . (Entrambe le affermazioni sono corrette, ovviamente.)P=DTiome(nO(1))P=DTiome(nΘ(1))
JeffE l'

@JeffE, la considero un'uguaglianza tra insiemi di funzioni, ma hai ragione, puoi anche pensarla come un limite superiore in un senso più generale.
Kaveh

@JeffE In realtà, , poiché D T I M E ( Θ ( n log n ) ) P ma D T I M E ( Θ ( n log n ) ) D T I M E ( n Θ ( 1 ) ) =PDTioME(nΘ(1))DTioME(Θ(nceppon))P . DTioME(Θ(nceppon))DTioME(nΘ(1))=
David Richerby,
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.