5.1 KiB
Notazione asintotica
La notazione asintotica è un sistema per stimare velocemente il costo di un algoritmo complesso.
Ci permette di confrontare velocemente il caso peggiore degli algoritmi.
In particolare, consideriamo il rapporto tra il numero di operazioni nel caso peggiore e la dimensione dell'input.
Limiti
Possiamo dare a questa stima dei limiti, superiore e inferiore, che rappresenteranno rispettivamente un costo che non sarà mai superato e un costo che verrà sempre superato.
Chiameremo questi limiti upper bound e lower bound; la loro combinazione darà un tight bound.
L'obiettivo sarà di ricavare i bound più precisi possibile per un dato algoritmo, ovvero l'upper bound più basso e il lower bound più alto.
O grande
"O grande"
O di g(n) "big-O"
Per rappresentare la stima, useremo una notazione particolare, detta O grande, con la seguente proprietà:
- Date due funzioni
f(n) : N -> R
eg(n) : N -> R
, diremo chef(n) ∈ O(g(n))
se e soltanto se∃ c > 0, n ≥ n_0
tali che∀ n ≥ 0, f(n) ≤ c * g(n)
Quando una funzione è O grande di un altra, significa che asintoticamente, la funzione in O grande è sempre maggiore di quella che sta venendo stimata.
Ipotesi
f(n) = 2n² + 3n + 6
g(n) = n²
Tesi
f(n) ∈ O(n²)
.Svolgimento
Scrivo una disequazione, lasciando intatto il termine noto:
2n² + 3n + 6 ≤ 2n² + 3n² + 6
n² ≤ 2n² + 3n² + n² = 6n²
pern ≥ 3
Sappiamo, allora, che
2n² + 3n + 6 ≤ 6n²
.
Espressioni di O grande
Questa tabella rappresenta le espressioni di O grande più comunemente utilizzate, in ordine dalla più forte alla più debole.
Più forte significa che, per ogni riga della tabella, tutte le righe sottostanti sono contenute nell'espressione.
Ad esempio,
O(n) ∈ O(1)
.
Polinomiale
Molto spesso, noteremo che il tempo richiesto da una funzione è O grande di un polinomio di grado K, ovvero f(n) ∈ O(n^k)
.
Notiamo che in questi casi, possiamo semplificare l'O grande al grado massimo del polinomio.
Ad esempio,
O(n² + n + 1) = O(n²)
.
Dimostrazione
Proprietà di O grande
f(n) ∈ O(g(n)) -> ∀ a > 0, a * f(n) ∈ O(g(n))
.f(n) ∈ O(g(n)), d(n) ∈ O(h(n)) -> f(n) + d(n) ∈ O(g(n) + h(n)) -> O(max\{g(n), h(n)\})
f(n) ∈ O(g(n)), d(n) ∈ O(h(n)) -> f(n) * d(n) ∈ O(g(n) * h(n))
In pratica, se una funzione è la somma di più termini, basta guardare l'O()
più grande tra tutti i suoi termini; se invece una funzione è un prodotto di più termini, si possono omettere le costanti, e l'O()
finale sarà dato dal prodotto degli O()
dei termini.
Lower bound
Possiamo anche stimare il lower bound, il limite inferiore: il numero minimo di operazioni che viene effettuato nel caso migliore con la massima dimensione dell'ingresso.
Ω()
"Omega"
Omega di g(n) "big-Omega"
Esiste un equivalente di O grande per il lower bound: è detto Omega grande, o più semplicemente Omega, e funziona nello stesso identico modo, solo... al contrario.
Diremo che f(n) ∈ Ω(g(n))
se e solo se ∃ c > 0, n_0 ≥ 0 : ∀ n ≥ n_0 f(n) ≥ c * g(n)
.
Espressioni di Ω()
Anche in questa tabella le espressioni sono dalla più forte alla più debole.
Tight bound
Quando upper e lower bound coincidono, allora otteniamo un tight bound.
θ()
"Theta"
Theta di g(n) "big-Theta"
Anche per il tight bound abbiamo una notazione equivalente a O grande e Omega grande: Theta grande!
Diciamo che f(n) ∈ θ(g(n))
se e solo se ∃ c_1, c_2 > 0, n_0 ≥ 0 : ∀ n ≥ n_0, c_1 * g(n) ≤ f(n) ≤ c_2 * g(n)
.
Ha la particolarità che non valgono tutte le proprietà degli altri due: va usata quindi con cautela!