Complessità computazionale
In questa pagina 8
In questa pagina 7
Idea
Definizione (caso peggiore, migliore e medio). Si misura il numero di operazioni elementari (assegnamenti, confronti, operazioni aritmetiche, accessi per indice) in funzione della dimensione dell'input (lunghezza della lista, numero di cifre...). Il tempo in secondi dipende dalla macchina; la crescita al crescere di no.
- Caso peggiore: massimo numero di operazioni tra gli input di dimensione (è quello che si dà di solito: è una garanzia).
- Caso migliore: minimo.
- Caso medio: media su una distribuzione degli input.
Esempio. Nella ricerca lineare su una lista di elementi il caso migliore costa confronto e il caso peggiore .
Esempio, ricerca lineare di x in una lista di elementi: caso migliore 1 confronto (primo elemento), caso peggiore (assente o ultimo).
Notazione O-grande
Definizione (notazione O-grande). se esistono e tali che per ogni : cresce al più come , a meno di costanti.
Regole pratiche:
- si tiene solo il termine dominante e si tolgono le costanti: ;
- passi in sequenza: si sommano (vince il maggiore);
- cicli annidati: si moltiplicano.
Esempio. per , quindi con e .
Esistono anche (limite inferiore: cresce almeno come) e (stessa crescita: sia sia ).
Classi di crescita
Definizione (classi di crescita)
Classe Nome Esempio costante accesso v[i],appendlogaritmica ricerca binaria lineare ricerca lineare, somma, massimo quasi lineare merge sort, sortedquadratica selection sort, insertion sort, tutte le coppie esponenziale fibricorsivo ingenuo, tutti i sottoinsiemi
Esempio. Con e operazioni al secondo, operazioni richiedono circa s e circa minuti.
Con e operazioni al secondo: richiede circa 0,02 s, circa 17 minuti, è impossibile.
Contare i passi
for i in range(n): # n volte
s += v[i] # O(1)
# totale O(n)
for i in range(n):
for j in range(i + 1, n): # n-1, n-2, ..., 0 volte
... # totale n(n-1)/2 = O(n^2)
i = n
while i > 1:
i //= 2 # i si dimezza: log2(n) iterazioni -> O(log n)Proprietà (equazioni di ricorrenza del costo). Ricorsione: si scrive l'equazione di ricorrenza del costo .
fattoriale: → .- ricerca binaria: → .
- merge sort: → .
fibingenuo: → esponenziale.
Esempio. fattoriale(5) fa chiamate (), coerente con .
Costi nascosti in Python
Una riga di Python non è sempre :
| Operazione | Costo |
|---|---|
x in lista, lista.index(x), lista.remove(x), min, max, sum |
|
lista.insert(0, x), lista.pop(0) |
|
slicing v[a:b], v.copy(), s + t |
proporzionale alla lunghezza del risultato |
x in insieme, d[k], k in d |
in media (vedi Dizionari e insiemi in PythonADT mappa e insieme; dict con chiavi hashable, accesso, get, iterazione, conteggi e raggruppamenti; set e operazioni insiemistiche; tabelle hash e costo O(1) medio; Counter e defaultdict.Dizionari e insiemi in Python →) |
sorted(v), v.sort() |
# O(n^2): "in" su una lista dentro un ciclo
dup = any(v[i] in v[i+1:] for i in range(len(v)))
# O(n): insieme
dup = len(set(v)) != len(v)Misurare i tempi
import time
t0 = time.perf_counter()
risultato = funzione(dati)
print(f"{time.perf_counter() - t0:.4f} s")Proprietà (effetto del raddoppio di n sul tempo). Raddoppiando : un algoritmo lineare raddoppia il tempo, uno quadratico lo quadruplica.
Esempio. Se con un algoritmo quadratico impiega s, con ne servono circa .
Spazio
Analogamente si misura la memoria aggiuntiva: se si usano poche variabili, se si crea una copia della lista; la ricorsione usa spazio di stack proporzionale alla profondità.
Errori tipici
- Considerare un
insu lista o uno slicing. - Confondere caso migliore e caso peggiore.
- Pensare che le costanti non contino mai: a parità di classe contano, ma per grande la classe vince.
Versione ripasso
Idea
Numero di operazioni elementari in funzione della dimensione dell'input .
- Caso peggiore: massimo numero di operazioni (garanzia).
- Caso migliore: minimo.
- Caso medio: media sulla distribuzione degli input.
Notazione O-grande
se esistono e tali che per ogni : cresce al più come .
- Si tiene solo il termine dominante e si tolgono le costanti: .
- Passi in sequenza: si sommano (vince il maggiore).
- Cicli annidati: si moltiplicano.
- Esistono anche (limite inferiore) e (stessa crescita).
Classi di crescita
| Classe | Nome | Esempio |
|---|---|---|
| costante | accesso v[i], append |
|
| logaritmica | ricerca binaria | |
| lineare | ricerca lineare, somma, massimo | |
| quasi lineare | merge sort, sorted |
|
| quadratica | selection sort, insertion sort | |
| esponenziale | fib ricorsivo ingenuo |
Contare i passi e Ricorrenze
- Ciclo semplice: .
- Cicli annidati triangolari: .
- Dimezzamento (
i //= 2): . - Ricorrenze :
fattoriale: .- ricerca binaria: .
- merge sort: .
fibingenuo: esponenziale.
Costi nascosti in Python
x in lista,index,remove,min,max,sum,insert(0),pop(0): .- Slicing
v[a:b],v.copy(),s + t: proporzionale alla lunghezza del risultato. x in insieme,d[k]: in media (vedi Dizionari e insiemi in PythonADT mappa e insieme; dict con chiavi hashable, accesso, get, iterazione, conteggi e raggruppamenti; set e operazioni insiemistiche; tabelle hash e costo O(1) medio; Counter e defaultdict.Dizionari e insiemi in Python →).sorted(v): .
Spazio
Memoria aggiuntiva: se poche variabili, per copie o strutture dati; la ricorsione usa stack proporzionale alla profondità.
Errori tipici
Considerare un in su lista o uno slicing; confondere caso migliore e peggiore.