Download as pdf or txt
Download as pdf or txt
You are on page 1of 22

1 Complessità degli algoritmi

Un algoritmo è tanto più efficiente quanto


minori sono le risorse di calcolo che impiega
durante la sua esecuzione
le risorse di calcolo sono il tempo (impiegato per effettuare
la computazione) e lo spazio (quantità di memoria
impiegata per effettuare la computazione)
considereremo solo il tempo
Il tempo speso nell’esecuzione di una funzione è
considerato un costo
costo computazionale o complessità computazionale della
funzione
dipende da vari fattori

Complessità degli algoritmi 2


L’analisi
analisi di complessità di una algoritmo A ha lo
scopo di determinare la funzione di costo tA(N)
dell’algoritmo (sia esso un programma od una
funzione/sottoprogramma)
stima il tempo di esecuzione di A
espressa come numero di operazioni elementari da
eseguire: assegnazioni, valutazione di condizioni, ecc.
in modo parametrico rispetto alla dimensione N dell’input
dimensione dell’input:
dell’input numerosità dell’insieme dei dati
elementari in ingresso (esempio: numero di elementi
dell’array da elaborare)

Complessità degli algoritmi 3


/* Funzione che calcola la somma degli elementi
di un array x */
int somma_array(int* x, int n) {
int somma = 0; //somma degli elementi di x
int i=0; //scandisce l'array
while (i<n){
somma = somma + a[i];
i++;
}
return somma;
}

Complessità degli algoritmi 4


Analisi di complessità della funzione
int somma_array(
somma_array(int*
int* x, int n)
funzione di costo tsommaArray(N)
N è il numero di elementi di x
espressa come numero di operazioni elementari
tsomma_array(N) = 3N + 4
Il numero tsomma_array(N) è da considerarsi
commisurato al tempo di esecuzione di
somma_array quando x ha lunghezza N
ad esempio
tsomma_array(10) = 34
tsomma_array(100) = 304

Complessità degli algoritmi 5


// Funzione che calcola la somma degli
elementi di un array a
int somma_array(int* x, int n) {
int somma = 0; N+1
int i=0;
1 while(i<n){
somma = somma + x[i];
1
i++;
N
} N
return somma;
} 1

tsomma_array(N) = 1 + 1 + (N+1) + N + N + 1 = 3N + 4

Complessità degli algoritmi 6


Modello di costo
un modello che descrive il costo delle operazioni
elementari
quali sono le operazioni elementari
quanto costa l’esecuzione di ciascuna operazione elementare
quanto costa l’esecuzione di operazioni composte

Complessità degli algoritmi 7


Operazione s Costo ts di una esecuzione di s

operazione o istruzione semplice:


(assegnazione, valutazione di
1
condizione, incremento, istruzione
return, ecc.)

blocco: { s1; s2; ... sK; } ts1 + ts2 + ... + tsK


istruzione condizionale: tcond + ts1 – se cond è true
if (cond) s1 else s2 tcond + ts2 – se cond è false
istruzione ripetitiva:
while (cond) s –
(m+1) tcond + m ts
nell’ipotesi che il corpo del while
venga eseguito m volte

invocazione di funzione f(p1, ..., pK) tf + tp1 + ... + tpK

Complessità degli algoritmi 8


Calcolare la funzione di costo della seguente
funzione, nell’ipotesi che a sia bidimensionale,
composto da R righe e C colonne

// Calcola la somma degli elementi dell’array di array a


int somma_matrice(int** x, int r, int c) {
/* scandisce e somma gli elementi di x, come somma
delle somme degli elementi delle righe di x */
int somma = 0, i;
for (i=0; i<r; i++)
somma += somma_array(x[i], c);
return somma;
}

Complessità degli algoritmi 9


Componenti della funzione di costo
tsomma_matrice (N), con N=RC
1 per l’operazione fuori dall’istruzione ripetitiva
1 per l’inizializzazione dell’istruzione ripetitiva
R+1 per la condizione dell’istruzione ripetitiva
R per l’incremento dell’istruzione ripetitiva
R volte il costo dell’esecuzione del corpo
ciascuna esecuzione del corpo comprende una invocazione di
somma_array usando come parametro un array lungo C
quindi ha costo tsomma_array (C) = 3C+4

Tsomma_matrice(N) = 1+1+R+1+R+R(3C+4) = 3RC + 6R + 3 =


= 3N + 6N1/2 + 3 (assumendo R=C)

Complessità degli algoritmi 10


In genere, il costo computazionale di un metodo
non dipende solo dalla dimensione dei suoi dati di
ingresso
può dipendere anche dal valore dei suoi dati d’ingresso

// Calcola il numero di occorrenze di v nell’array a


int occorrenze(int* x, int n, int v) {
int i, occ=0; // numero di occorrenze di v in x
for (i=0; i<n; i++)
if (x[i]==v)
occ++;
return occ;
}

Complessità degli algoritmi 11


Si consideri il seguente array x
3 2 3

se v vale 0, il costo dell’esecuzione di occorrenze è 13


se invece v vale 3, il costo dell’esecuzione è 15
in generale

toccorrenze(N) = 3N+K+4

N è la lunghezza di a
K è il numero di elementi di x che sono uguali a v (0≤K≤N)

Complessità degli algoritmi 12


Altro esempio:

int ricerca(int* x, int n, int chiave) {


int i;
for (i=0; i<n; i++)
if (x[i]==chiave)
return i;
return -1;
}

Quanti passi elementari vengono eseguiti dall’algoritmo?

Complessità degli algoritmi 13


Per esprimere la funzione di costo di un metodo
in modo dipendente solo dalla dimensione dei
dati di ingresso
la funzione di costo viene determinata nel caso peggiore
caso peggiore per il metodo occorrenze
gli elementi di x sono tutti uguali a v (ossia K = N)
il costo è 4N+4
la funzione di costo, nell’ipotesi (comune) di analisi di caso
peggiore, stima il costo massimo dell’esecuzione del
metodo
il costo minimo (analisi di caso migliore) è poco significativo
il costo medio è difficile da definire e calcolare

Complessità degli algoritmi 14


// Verifica se x contiene una coppia di
// elementi uguali
bool duplicati(int* x, int n) {
// cerca una coppia di elementi uguali
// esaminando tutte le coppie di elementi
// distinti
bool esiste = false;
for (i=0; i<n && !esiste; i++)
for (j=0; j<n && !esiste; j++)
if (i!=j && x[i]==x[j])
esiste = true;
return esiste;
}
tduplicati(N) = 4N2 + 4N + 4

Complessità degli algoritmi 15


Funzione di costo asintotico tf(N) di una
funzione f
ordine di grandezza del costo di esecuzione di f in
funzione della dimensione N dei dati di ingresso
descrive l’andamento della funzione di costo per N tendente
all’infinito:
1) si eliminano i termini di ordine inferiore
2) si eliminano i fattori moltiplicativi costanti
ad esempio
tduplicati(N) = 4N2 + 4N + 4 (funzione di costo)
tduplicati(N) = N2 (funzione di costo asintotico)
Motivazioni per l’analisi asintotica
il modello di costo è già approssimato
siamo interessati all’ordine di grandezza ed al tasso di
crescita del tempo (piuttosto che alla forma “esatta”)
Complessità degli algoritmi 16
Nell’analisi asintotica viene fatto in genere
riferimento al alcune funzioni (notevoli) che
hanno una forma “semplice”, tra cui:
K – funzione costante (K=cost.)
log N – funzione logaritmica
N1/2 – funzione radice quadrata
N – funzione lineare
N2 – funzione quadratica
NK – funzione polinomiale (K=cost.)
KN – funzione esponenziale (K=cost.)

Complessità degli algoritmi 17


Si definisce operazione dominante,
dominante l’istruzione o
gruppo di istruzioni che vengono eseguite più
frequentemente
possiamo anche avere più operazioni dominanti in un
programma
il costo asintotico di un algoritmo è pari al costo
(asintotico) dell’esecuzione della sola operazione
dominante

Complessità degli algoritmi 18


/*Funzione che calcola la somma degli
elementi di un array x */
int somma_array(int* x, int n) {
int somma = 0;
int i=0; //scandisce l'array
while(i<n){
somma = somma + x[i];
i++;
}
return somma;
}

Complessità degli algoritmi 19


// Verifica se a contiene una coppia di elementi
// uguali
bool duplicati(int* x, int n) {
// cerca una coppia di elementi uguali
// esaminando tutte le coppie di elementi
// distinti
bool esiste = false;
for (i=0; i<n; i++)
for (j=0; j<n; j++)
if (i!=j && x[i]==x[j])
esiste = true;
return esiste;
}

Complessità degli algoritmi 20


Le tecniche di analisi di complessità degli
algoritmi possono essere usate per l’analisi di
complessità dei problemi
la complessità di un problema è la complessità
dell’algoritmo più efficiente tra quelli lo risolvono

Classi di complessità dei problemi:


problemi
Trattabili:
Trattabili esiste un algoritmo ed è efficiente (costo al più
polinomiale)
Intrattabili:
Intrattabili esiste un algoritmo, ma non è efficiente (costo
super-polinomiale/esponenziale)
Indecidibili:
Indecidibili non esiste un algoritmo (problema della
fermata: dato un algoritmo ed un suo input decidere se
l’algoritmo di fermerà sull’input dato)

Complessità degli algoritmi 21


Costo computazionale per alcuni classi di funzioni
caratterizzate da complessità (asintotica) differente, per
alcuni possibili valori della dimensione N dell’input
si ipotizza che il tempo di esecuzione di ciascuna operazione
sia 1ns (10-9 s)

t(N) \ N 10 100 1 000 10 000


800 N 8 µs 80 µs 800 µs 8 ms
120 N log N 4 µs 80 µs 1.2 ms 16 ms
20 N2 2 µs 200 µs 20 ms 2 sec
0.1 N4 1 µs 10 ms 100 sec 11 giorni
0.5 2N 0.5 µs 1013 anni 10284 anni
1000 volte l’età dell’universo

Complessità degli algoritmi 22

You might also like