Sei sulla pagina 1di 20

Linguaggi e Sistemi di

Programmazione
Corso di Laurea in Ingegneria Gestionale

Marco Lippi
marco.lippi@unimore.it

04 - Teoria della complessità


Complessità
Come si valuta l’efficienza di un algoritmo?
• Numero di operazioni eseguite (tempo)
• Numero di variabili allocate (memoria)

La teoria complessità computazionale studia la


performance degli algoritmi in termini di risorse.
Ci occuperemo principalmente del caso temporale.
Complessità
Nota sulla complessità spaziale
• Occupazione massima della memoria
• Occupazione media della memoria

Nel primo caso devo considerare il valore massimo


di occupazione raggiunto durante l’esecuzione del
programma; nel secondo caso devo stimare come
questa varia nel tempo e farne una media…
Complessità
Chiaramente ci sono aspetti anche più importanti
(correttezza, costo, sicurezza, facilità d’uso, ecc…)
ma in alcuni contesti è una proprietà cruciale
• Sistemi in tempo reale
• Determina ciò che è fattibile con risorse ragionevoli

Come misurare la complessità temporale?


Svilupperemo un modello astratto. Perché?
Complessità
E’ sufficiente misurare il tempo di esecuzione di un
programma per valutare l’algoritmo? No! Perché il
tempo può dipendere da moltissimi parametri…
• Bravura del programmatore
• Linguaggio di programmazione utilizzato
• Istruzioni di basso livello
• Processore, memoria, cache, etc.
• Sistema operativo, altri processi in esecuzione…
Complessità
Analisi asintotica
Detta n la dimensione dell’input di un algoritmo, si
analizza la crescita del tempo di calcolo T(n) al
tendere di n verso l’infinito, dove T(n) si associa al
numero di passi base (che hanno costo unitario)

Notazione 𝝝
Nell’analisi asintotica, si eliminano termini di ordine
inferiore e si ignorano costanti moltiplicative e additive
Complessità

Si dice che
f (n) = ⇥(g(n))

se
9 k1 > 0, k2 > 0, n0 > 0 s.t. 8n > n0
k1 · g(n)  f (n)  k2 · g(n)
Complessità
Alcuni esempi di classi di complessità…
• 𝝝(1) → tempo costante (indipendente da n)

• 𝝝(log(n)) → tempo logaritmico

• 𝝝(nk) → tempo polinomiale

• 𝝝(2n) → tempo esponenziale

• 𝝝(n!) → tempo fattoriale


Complessità
Esempio — Somma degli elementi di una lista

i ← 0 2 ASSEGNAMENTI
sum ← 0
while i <= len(L) { N ITERAZIONI
CIASCUNA CON 2 SOMME
sum ← sum + L[i] E 2 ASSEGNAMENTI
i ← i + 1
} TOTALE: 2 + N * (2 + 2) = 2 + 4 * N

T (n) = ⇥(n)
Complessità
Esempio — Cicli annidati

i ← 0
while i <= len(L) {
j ← i + 1 COSA FA QUESTO PROGRAMMA?
found ← False
while j <= len(L) {
if L[i] > L[j]
found ← True
}
if found = False
print L[i] <latexit sha1_base64="z7cf8AAgf9rA5NVM63QZMmvrARQ=">AAACAXicbVDLSgNBEJz1GdfXqhfBy2BWSC5hNyB6EYJePEbIC5I1zE46yZDZ2WVmVgghXvwVLx4U8epfePNvnDwOmljQUFR1090VJpwp7Xnf1srq2vrGZmbL3t7Z3dt3Dg5rKk4lhSqNeSwbIVHAmYCqZppDI5FAopBDPRzcTPz6A0jFYlHRwwSCiPQE6zJKtJHazrHr2pWcyOMr3Kr0QZOcuC/mbddtO1mv4E2Bl4k/J1k0R7ntfLU6MU0jEJpyolTT9xIdjIjUjHIY261UQULogPSgaaggEahgNP1gjM+M0sHdWJoSGk/V3xMjEik1jELTGRHdV4veRPzPa6a6exmMmEhSDYLOFnVTjnWMJ3HgDpNANR8aQqhk5lZM+0QSqk1otgnBX3x5mdSKBf+84N0Vs6XreRwZdIJOUQ756AKV0C0qoyqi6BE9o1f0Zj1ZL9a79TFrXbHmM0foD6zPHxV5k3I=</latexit>

2
i ← i + 1 T (n) = ⇥(n )
}
Complessità
Il tempo di esecuzione di un algoritmo
• dipende dalla dimensione dell’input n
• dipende dalla specifica istanza di input

Solitamente si conducono diversi tipi di analisi


• Caso pessimo (tempo massimo per input di dim. n)
• Caso medio (tempo medio per input di dim. n)
• Caso ottimo → inutile!
Complessità
Esempio — Problema del commesso viaggiatore

Un commesso viaggiatore deve visitare n città


esattamente una volta e tornare al punto di origine.
Data la lista delle città e le loro distanze, qual è il
percorso con distanza minima?

• Problema NP-difficile
• Soluzione per forza bruta → n!
• Soluzione con programmazione dinamica → 2n
Complessità

Problema NP-difficile
Può essere risolto in tempo polinomiale da una
macchina di Turing non deterministica
Nella pratica, significa che non si conoscono algoritmi
polinomiali per una macchina di Turing deterministica,
quindi per un calcolatore moderno
Sono algoritmi con complessità non-polinomiale
Complessità

Esempio — Numeri di Fibonacci

Determinare la complessità di queste tre varianti


• Algoritmo iterativo
• Algoritmo ricorsivo (divide-et-impera)
• Algoritmo con memoization
Complessità
Esempio — Numeri di Fibonacci

Algoritmo iterativo

Sequenza di operazioni che costruiscono in modo


iterativo la serie di Fibonacci: complessità lineare!

T (n) = ⇥(n)
Complessità
Esempio — Numeri di Fibonacci

Algoritmo ricorsivo

La chiamata ricorsiva produce una struttura ad albero,


che ricalcola anche più volte lo stesso risultato
intermedio: complessità esponenziale!

n
<latexit sha1_base64="4JMSAPrQBl2J0cW11mBBWm4p/m8=">AAAB/3icbVBNS8NAEN34WetXVPDiZbEV2ktJCqIXoejFY4V+QRvLZjtpl242YXcjlNiDf8WLB0W8+je8+W9M2hy09cHA470ZZua5IWdKW9a3sbK6tr6xmdvKb+/s7u2bB4ctFUSSQpMGPJAdlyjgTEBTM82hE0ogvsuh7Y5vUr/9AFKxQDT0JATHJ0PBPEaJTqS+eVxslEQZX+FeYwSa4FL1XpSL+b5ZsCrWDHiZ2BkpoAz1vvnVGwQ08kFoyolSXdsKtRMTqRnlMM33IgUhoWMyhG5CBfFBOfHs/ik+S5QB9gKZlNB4pv6eiImv1MR3k06f6JFa9FLxP68bae/SiZkIIw2Czhd5Ecc6wGkYeMAkUM0nCSFUsuRWTEdEEqqTyNIQ7MWXl0mrWrHPK9ZdtVC7zuLIoRN0ikrIRheohm5RHTURRY/oGb2iN+PJeDHejY9564qRzRyhPzA+fwB6GZMs</latexit>

T (n) = ⇥(2 )
Complessità
Esempio — Numeri di Fibonacci

Algoritmo ricorsivo

Fonte: quora.com
Complessità

Esempio — Numeri di Fibonacci

Algoritmo con memoization

La chiamata ricorsiva stavolta viene interrotta nel


caso in cui il risultato sia presente nella “cache”, per
cui il numero di operazioni torna ad essere lineare

T (n) = ⇥(n)
Complessità
Esempio — Torre di Hanoi

Determinare la complessità dell’algoritmo ricorsivo

Per spostare n dischi, è necessario spostare prima


n-1 dischi, poi l’ultimo disco, e poi di nuovo gli n-1.
(
<latexit sha1_base64="spebVNWFW1r8XPrx981M/f86l48=">AAACTXicbVFNaxsxENU6zdfmy02PvQyxE2JCzK6hpJeAaS89umAnAcsYrXZsi2i1W0kbMIv/YC6B3PIveumhIYTKH4HGyYDg8d6bGekpyqQwNggevNLKh9W19Y1Nf2t7Z3ev/HH/wqS55tjhqUz1VcQMSqGwY4WVeJVpZEkk8TK6/j7VL29QG5Gqth1n2EvYUImB4Mw6ql+Oq1W/faxqcA4+jXAoVMHdODPxeT+AIzAI9FfOYlDnAVDqN4DyOLXgek7DGpzAso0OEUKfoopfBlWr/XIlqAezgrcgXIAKWVSrX76nccrzBJXlkhnTDYPM9gqmreASJz7NDWaMX7Mhdh1ULEHTK2ZpTODQMTEMUu2OsjBj/+8oWGLMOImcM2F2ZJa1Kfme1s3t4GuvECrLLSo+XzTIJdgUptFCLDRyK8cOMK6FuyvwEdOMW/cBvgshXH7yW3DRqIdf6sHPRqX5bRHHBvlMDsgxCckZaZIfpEU6hJNb8pv8JY/enffHe/Ke59aSt+j5RF5Vaf0f7tus0A==</latexit>

c0 se n = 0
T (n) =
2 · T (n 1) + c0 se n 1

n
<latexit sha1_base64="4JMSAPrQBl2J0cW11mBBWm4p/m8=">AAAB/3icbVBNS8NAEN34WetXVPDiZbEV2ktJCqIXoejFY4V+QRvLZjtpl242YXcjlNiDf8WLB0W8+je8+W9M2hy09cHA470ZZua5IWdKW9a3sbK6tr6xmdvKb+/s7u2bB4ctFUSSQpMGPJAdlyjgTEBTM82hE0ogvsuh7Y5vUr/9AFKxQDT0JATHJ0PBPEaJTqS+eVxslEQZX+FeYwSa4FL1XpSL+b5ZsCrWDHiZ2BkpoAz1vvnVGwQ08kFoyolSXdsKtRMTqRnlMM33IgUhoWMyhG5CBfFBOfHs/ik+S5QB9gKZlNB4pv6eiImv1MR3k06f6JFa9FLxP68bae/SiZkIIw2Czhd5Ecc6wGkYeMAkUM0nCSFUsuRWTEdEEqqTyNIQ7MWXl0mrWrHPK9ZdtVC7zuLIoRN0ikrIRheohm5RHTURRY/oGb2iN+PJeDHejY9564qRzRyhPzA+fwB6GZMs</latexit>

T (n) = ⇥(2 )
Complessità
Esempio — Torre di Hanoi

T(n) = 2 * T(n-1) + 1
T(n) = 2 * ( 2 * T(n-2) + 1) + 1
T(n) = 22 * T(n-2) + 21 + 20
T(n) = 2k * T(n-k) + 2k-1 + 2k-2 + ... + 20

T(n) = 2n - 1 supponendo T(0) = 0

Potrebbero piacerti anche