Che cos'è O (...) e come posso calcolarlo?


31

Aiuto! Ho una domanda in cui devo analizzare il Big-O di un algoritmo o di un codice.

  • Non sono sicuro di cosa sia Big-O o di come si colleghi a Big-Theta o ad altri mezzi per analizzare la complessità di un algoritmo.

  • Non sono sicuro se Big-O si riferisca al tempo di esecuzione del codice o alla quantità di memoria necessaria (compromessi spazio / tempo).

  • Ho i compiti di Computer Science in cui ho bisogno di fare alcuni loop, forse un algoritmo ricorsivo, e inventare il Big-O per questo.

  • Sto lavorando a un programma in cui posso scegliere tra due strutture di dati o algoritmi con un Big-O noto e non sono sicuro di quale scegliere.

Come faccio a capire come calcolare e applicare Big-O al mio programma, compiti a casa o conoscenza generale dell'informatica?

Nota: questa domanda è un obiettivo canonico dupe per altre domande Big-O come determinato dalla comunità . È intenzionalmente ampio poter contenere una grande quantità di informazioni utili per molte domande su Big-O. Si prega di non usare il fatto che sia così ampio come indicazione che domande simili sono accettabili.


1
Solo una nota, questa domanda è in discussione qui su meta .
Enderland,

2
Una grande risorsa per iniziare sarebbe il corso dell'Accademia di Khan (Thomas Cormen del CLRS è uno degli scrittori). Questa è stata una grande risorsa anche per me come laureato in CS. khanacademy.org/computing/computer-science/algorithms
Sudip Bhandari

3
Alle persone che segnalano questa domanda: leggi il sottotesto in fondo alla domanda e segui quel link prima di contrassegnare o votare per chiudere.

Risposte:


22

La O (...) si riferisce alla notazione Big-O, che è un modo semplice per descrivere quante operazioni un algoritmo richiede di fare qualcosa. Questo è noto come complessità temporale .

Nella notazione Big-O, il costo di un algoritmo è rappresentato dalla sua operazione più costosa in grandi numeri. Se un algoritmo prendesse delle misure, verrebbe rappresentato O (n 3 ). Un algoritmo che conta ogni elemento in un elenco opererebbe in tempo O (n), chiamato tempo lineare.n3 + n2 + n

Per un elenco dei nomi e degli esempi classici su Wikipedia: ordini di funzioni comuni

Materiale correlato:


6
Nota: big O non misura intrinsecamente il tempo o lo spazio o qualsiasi cosa particolare. Limita semplicemente la crescita asintotica di una funzione (fino a una costante). Quella funzione potrebbe essere il tempo, lo spazio, ecc. Di un algoritmo in funzione della sua lunghezza di input, e più comunemente in un contesto CS è il tempo, ma non è necessariamente.
Ripristina Monica

23

Quali sono le funzioni asintotiche? Che cos'è un asintoto, comunque?

Data una funzione f (n) che descrive la quantità di risorse (tempo CPU, RAM, spazio su disco, ecc.) Consumata da un algoritmo quando applicata a un input di dimensione n , definiamo fino a tre notazioni asintotiche per descriverne le prestazioni per grande n .

Un asintoto (o funzione asintotica) è semplicemente un'altra funzione (o relazione) g (n) a cui f (n) si avvicina sempre di più man mano che n diventa sempre più grande, ma non raggiunge mai del tutto. Il vantaggio di parlare di funzioni asintotiche è che sono generalmente molto più semplici da parlare anche se l'espressione per f (n) è estremamente complicata. Le funzioni asintotiche sono utilizzate come parte delle notazioni di delimitazione che limitano f (n) sopra o sotto.

(Nota: nel senso qui impiegato, le funzioni asintotiche sono vicine alla funzione originale solo dopo aver corretto un fattore diverso da zero, poiché tutte e tre le notazioni big-O / Θ / Ω ignorano questi fattori costanti dalla loro considerazione.)

Quali sono le tre notazioni di delimitazione asintotica e come sono diverse?

Tutte e tre le notazioni vengono utilizzate in questo modo:

f (n) = O (g (n))

dove f (n) qui è la funzione di interesse, e g (n) è un'altra funzione asintotica con cui stai provando ad approssimare f (n) . Questo non dovrebbe essere preso come uguaglianza in senso rigoroso, ma un'affermazione formale tra quanto velocemente f (n) cresce rispetto a n rispetto a g (n) , poiché n diventa grande. I puristi useranno spesso la notazione alternativa f (n) ∈ O (g (n)) per sottolineare che il simbolo O (g (n)) è in realtà un'intera famiglia di funzioni che condividono un tasso di crescita comune.

La notazione Big-ϴ (Theta) afferma un'uguaglianza sulla crescita di f (n) fino a un fattore costante (ne parleremo più avanti). Si comporta in modo simile a un =operatore per i tassi di crescita.

La notazione Big-O descrive un limite superiore sulla crescita di f (n) . Si comporta in modo simile a un operatore per i tassi di crescita.

La notazione Big-Ω (Omega) descrive un limite inferiore su una crescita di f (n) . Si comporta in modo simile a un operatore per i tassi di crescita.

Esistono molte altre notazioni asintotiche , ma non si verificano quasi altrettanto spesso nella letteratura informatica.

Le notazioni Big-O e il suo genere sono spesso un modo per confrontare la complessità temporale .

Cos'è la complessità temporale?

La complessità temporale è un termine elaborato per la quantità di tempo T (n) impiegata per l'esecuzione di un algoritmo in funzione della sua dimensione di input n . Questo può essere misurato in termini di tempo reale (ad es. Secondi), numero di istruzioni della CPU, ecc. Di solito si presume che l'algoritmo verrà eseguito sul computer dell'architettura von Neumann di tutti i giorni . Ma ovviamente puoi usare la complessità del tempo per parlare di sistemi di elaborazione più esotici, dove le cose potrebbero essere diverse!

È anche comune parlare della complessità dello spazio usando la notazione Big-O. La complessità dello spazio è la quantità di memoria (memoria) richiesta per completare l'algoritmo, che potrebbe essere RAM, disco, ecc.

È possibile che un algoritmo sia più lento ma utilizzi meno memoria, mentre un altro sia più veloce ma utilizzi più memoria. Ognuno può essere più appropriato in circostanze diverse, se le risorse sono vincolate in modo diverso. Ad esempio, un processore incorporato può avere una memoria limitata e favorire l'algoritmo più lento, mentre un server in un data center può avere una grande quantità di memoria e favorire l'algoritmo più veloce.

Calcolo di Big-ϴ

Il calcolo del Big-ϴ di un algoritmo è un argomento che può riempire un piccolo libro di testo o all'incirca mezzo semestre di corso di laurea: questa sezione tratterà le basi.

Data una funzione f (n) in pseudocodice:

int f(n) {
  int x = 0;
  for (int i = 1 to n) {
    for (int j = 1 to n) {
      ++x;
    }
  }
  return x;
}

Qual è la complessità temporale?

Il ciclo esterno viene eseguito n volte. Per ogni volta che il ciclo esterno viene eseguito, il ciclo interno viene eseguito n volte. Questo mette il tempo di funzionamento in T (n) = n 2 .

Considera una seconda funzione:

int g(n) {
  int x = 0;
  for (int k = 1 to 2) {
    for (int i = 1 to n) {
      for (int j = 1 to n) {
        ++x;
      }
    }
  }
  return x;
}

L'anello esterno viene eseguito due volte. Il ciclo centrale viene eseguito n volte. Per ogni volta che il ciclo centrale viene eseguito, il ciclo interno viene eseguito n volte. Questo mette il tempo di funzionamento a T (n) = 2n 2 .

Ora la domanda è: qual è il tempo di esecuzione asintotico di entrambe le funzioni?

Per calcolare questo, eseguiamo due passaggi:

  • Rimuovi costanti. Poiché gli algoritmi aumentano nel tempo a causa degli input, gli altri termini dominano il tempo di esecuzione, rendendoli non importanti.
  • Rimuovi tutto tranne il termine più grande. Mentre n va all'infinito, n 2 supera rapidamente n .

La chiave qui è concentrarsi sui termini dominanti e semplificarli .

T (n) = n 2 ∈ ϴ (n 2 )
T (n) = 2n 2 ∈ ϴ (n 2 )

Se abbiamo un altro algoritmo con più termini, lo semplificheremmo usando le stesse regole:

T (n) = 2n 2 + 4n + 7 ∈ ϴ (n 2 )

La chiave di tutti questi algoritmi è che ci concentriamo sui termini più grandi e rimuoviamo le costanti . Non stiamo guardando il tempo di esecuzione effettivo, ma la relativa complessità .

Calcolo di Big-Ω e Big-O

Prima di tutto, tieni presente che nella letteratura informale , "Big-O" è spesso trattato come un sinonimo di Big-Θ, forse perché le lettere greche sono difficili da scrivere. Quindi, se qualcuno di punto in bianco ti chiede il Big-O di un algoritmo, probabilmente vogliono il suo Big-Θ.

Ora, se vuoi davvero calcolare Big-Ω e Big-O nei sensi formali definiti in precedenza, hai un grosso problema: ci sono infinite descrizioni Big-Ω e Big-O per ogni data funzione! È come chiedere quali siano i numeri inferiori o uguali a 42. Ci sono molte possibilità

Per un algoritmo con T (n) ∈ ϴ (n 2 ) , è necessario formulare una delle seguenti affermazioni formalmente valide:

  • T (n) ∈ O (n 2 )
  • T (n) ∈ O (n 3 )
  • T (n) ∈ O (n 5 )
  • T (n) ∈ O (n 12345 × e n )
  • T (n) ∈ Ω (n 2 )
  • T (n) ∈ Ω (n)
  • T (n) ∈ Ω (log (n))
  • T (n) ∈ Ω (log (log (n)))
  • T (n) ∈ Ω (1)

Ma non è corretto dichiarare T (n) ∈ O (n) o T (n) ∈ Ω (n 3 ) .

Qual è la complessità relativa? Quali classi di algoritmi ci sono?

Se confrontiamo due diversi algoritmi, la loro complessità man mano che l'input passa all'infinito aumenterà normalmente. Se osserviamo diversi tipi di algoritmi, possono rimanere relativamente gli stessi (diciamo, differendo per un fattore costante) o possono divergere notevolmente. Questo è il motivo per eseguire l'analisi Big-O: per determinare se un algoritmo funzionerà ragionevolmente con input di grandi dimensioni.

Le classi di algoritmi si suddividono come segue:

  • Θ (1) - costante. Ad esempio, la selezione del primo numero in un elenco richiederà sempre lo stesso tempo.

  • Θ (n) - lineare. Ad esempio, l'iterazione di un elenco richiederà sempre un tempo proporzionale alla dimensione dell'elenco, n .

  • Θ (log (n)) - logaritmico (la base normalmente non ha importanza). Gli algoritmi che dividono lo spazio di input in ogni passaggio, come la ricerca binaria, sono esempi.

  • Θ (n × log (n)) - tempi lineari logaritmici ("linearithmic"). Questi algoritmi in genere dividono e conquistano ( log (n) ) mentre ripetono ( n ) tutto l'input. Molti algoritmi di ordinamento popolari (merge sort, Timsort) rientrano in questa categoria.

  • Θ (n m ) - polinomiale ( n elevato a qualsiasi costante m ). Questa è una classe di complessità molto comune, spesso presente nei loop nidificati.

  • Θ (m n ) - esponenziale (qualsiasi costante m elevata a n ). Molti algoritmi ricorsivi e grafici rientrano in questa categoria.

  • Θ (n!) - fattoriale. Alcuni algoritmi grafici e combinatori sono complessità fattoriale.

Questo ha qualcosa a che fare con il caso migliore / medio / peggiore?

No. Big-O e la sua famiglia di notazioni parlano di una specifica funzione matematica . Sono strumenti matematici impiegati per aiutare a caratterizzare l'efficienza degli algoritmi, ma la nozione di migliore / medio / peggiore caso non è correlata alla teoria dei tassi di crescita qui descritta.

Per parlare del Big-O di un algoritmo, è necessario impegnarsi in uno specifico modello matematico di un algoritmo con esattamente un parametro n, che dovrebbe descrivere la "dimensione" dell'input, in qualunque senso sia utile. Ma nel mondo reale, gli input hanno una struttura molto più ampia delle loro lunghezze. Se questo era un algoritmo di ordinamento, che potrebbe alimentare nelle stringhe "abcdef", "fedcba"oppure "dbafce". Sono tutti della lunghezza 6, ma uno è già ordinato, uno è invertito e l'ultimo è solo un miscuglio casuale. Alcuni algoritmi di ordinamento (come Timsort) funzionano meglio se l'input è già ordinato. Ma come si può incorporare questa disomogeneità in un modello matematico?

L'approccio tipico è semplicemente supporre che l'input provenga da una distribuzione casuale e probabilistica. Quindi, si calcola la media della complessità dell'algoritmo su tutti gli input con lunghezza n. Questo ti dà un modello di complessità di caso medio dell'algoritmo. Da qui, puoi usare le notazioni Big-O / Θ / Ω come al solito per descrivere il comportamento medio del caso.

Ma se sei preoccupato per gli attacchi denial-of-service, potresti dover essere più pessimista. In questo caso, è più sicuro supporre che gli unici input siano quelli che causano la maggior quantità di dolore al tuo algoritmo. Questo ti dà un modello di complessità nel caso peggiore dell'algoritmo. Successivamente, puoi parlare di Big-O / Θ / Ω ecc . Del modello peggiore .

Allo stesso modo, puoi anche concentrare il tuo interesse esclusivamente sugli input con i quali l'algoritmo ha il minor numero di problemi per arrivare a un modello del caso migliore , quindi guarda Big-O / Θ / Ω ecc.


Questa è una buona risposta, ma Big-O e Big-Ω hanno poco a che fare con i casi peggiori e migliori. Sono limiti superiore e inferiore, ma possono entrambi applicarsi a entrambi i casi, ad esempio l'ordinamento per inserzione ha, nel migliore dei casi, una complessità temporale ϴ(n)(sia Big-O che Big-Ω) pur avendo, nel peggiore dei casi, una complessità temporale di ϴ(n²)(sia Big-O che Big-Ω).
Paolo

Inoltre, qualsiasi algoritmo, escluso l'algoritmo vuoto, è Ω(1)nei casi migliori, peggiori e medi, ma ciò è dovuto al fatto che è un limite inferiore e non ha nulla a che fare con il caso migliore dell'algoritmo.
Paolo

Le cose grandi non hanno nulla a che fare con il caso migliore o peggiore: questo è un malinteso comune. Sono semplicemente modi per stabilire se una funzione deterministica cresce più velocemente, più lentamente o allo stesso ritmo rispetto a un'altra. La nozione del caso migliore / peggiore esiste solo quando inizi a parlare della complessità tempo / spazio degli algoritmi reali, nel qual caso sorgono i fattori non deterministici e devi considerare la distribuzione di probabilità dei tuoi input. Anche allora, il caso migliore / peggiore si trova su un asse ortogonale a big-O / Omega.
Rufflewind,

@Rufflewind se pensi di poterlo descrivere meglio, quindi vai avanti. Ti rendi conto che questa è una risposta wiki della community, giusto?

"Prima di tutto, tieni presente che nella letteratura informale," Big-O "è spesso trattato come sinonimo di Big-Θ" -> Non solo nella letteratura informale. Il mio primo semestre su Complexity, tornato al college, ci ha insegnato la definizione di Big-O come se fosse Big-Θ. (Il nostro libro di testo ha usato quella definizione!) Mi ha confuso a morte quando sono andato a Complexity II e ho scoperto che i due non erano gli stessi.
T. Sar - Ripristina Monica il
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.