Algoritmi e complessità
La complessità
Complessità in tempo e spazio
Complessità asintotica
Algoritmi e complessità
Ricerca e ordinamento
La macchina di Turing e le classi di
complessità
Fondamenti di Informatica I  a.a. 2008-09
1
La complessità
Fondamenti di Informatica I  a.a. 2008-09
2
La complessità
L’analisi di complessità definisce le risorse teoricamente
consumate da un algoritmo
complessità temporale: tempo necessario all’esecuzione
dell’algoritmo
complessità spaziale: memoria necessaria all’esecuzione
dell’algoritmo
Poiché ad ogni algoritmo corrispondono più
implementazioni (più programmi), lo studio della
complessità non definisce esattamente il tempo e la
memoria usata: si concentra sulle proprietà che sono
indipendenti dell’implementazione fornendo un’idea di
quanto sia efficiente un algoritmo
Fondamenti di Informatica I  a.a. 2008-09
3
Che cosa si misura?  1
Complessità temporale
Si contano le istruzioni eseguite dall’algoritmo
Poiché le istruzioni potrebbero essere di natura diversa, si
individuano quelle che incidono principalmente sul tempo
di esecuzione
Le operazioni in virgola mobile: le più lente da eseguire per una
CPU; sono predominanti se il loro numero è paragonabile al numero
delle altre istruzioni
Le istruzioni di controllo (gli if) e le istruzioni più frequenti (sono
predominanti se sono in numero molto superiore alle altre
istruzioni)
Le istruzioni di accesso alla memoria secondaria e alle periferiche:
sono decine di migliaia di volte più lente delle istruzioni svolte nella
memoria principale; se un’applicazione ne richiede molte, queste
potrebbero essere predominanti (ad es., nei database, l’analisi di
complessità è concentrata sugli accessi al disco)
Fondamenti di Informatica I  a.a. 2008-09
4
Che cosa si misura?  2
Complessità spaziale
Si misurano le “posizioni” di memoria occupate dai dati
necessari allo svolgimento dell’algoritmo
La complessità spaziale sarà misurata relativamente alla
memoria principale se i dati dell’algoritmo possono essere
allocati in memoria principale, in base all’occupazione di
memoria
secondaria
quando
le
strutture
dati
dell’algoritmo sono troppo grandi per poter risiedere nella
memoria centrale
Fondamenti di Informatica I  a.a. 2008-09
5
Complessità asintotica
Lo studio della complessità si concentra su i casi in cui il
problema è grande:
non importa se un programma di contabilità impiega 1 o
100 millisecondi a calcolare il bilancio
cambia molto se il programma della segreteria impiega 1
o 10 secondi a trovare i dati di uno studente nell’archivio
Complessità asintotica
Definisce le risorse usate da un algoritmo al crescere della
dimensione del problema affrontato
Ad esempio: come cambia il tempo di accesso ai dati
quando cresce il numero degli studenti nell’archivio della
segreteria
Fondamenti di Informatica I  a.a. 2008-09
6
Complessità temporale asintotica  1
Formalmente, si usa il concetto matematico di ordine di
grandezza
sia n la dimensione del problema, cioè la dimensione dell’input
dell’algoritmo
sia T(n) il tempo impiegato per l’esecuzione dell’algoritmo
quando l’ingresso ha dimensione n
sia f(n) una qualsiasi funzione di n, ad esempio 3, n, n2, n5, 2n
Si dice che la complessità asintotica dell’algoritmo è dell’ordine
di f(n) e si scrive O (f(n)) se esiste una costante  tale che
T(n) f(n)
Osservazione importante: in base alla definizione data,
algoritmi che differiscono solo per una costante moltiplicativa
hanno lo stesso ordine di complessità
Esempio: due algoritmi che richiedono 4n e 7n operazioni
sono entrambi O (n)
Fondamenti di Informatica I  a.a. 2008-09
7
Complessità temporale asintotica  2
Informalmente…
L’ordine O (f(n)) fornisce una misura della complessità
temporale di ogni programma che implementa l’algoritmo
Esempio: Calcolare la somma degli elementi di un array
n: numero di elementi dell’array
complessità: O (n)
Fondamenti di Informatica I  a.a. 2008-09
8
Complessità media e relativa al caso peggiore
Un algoritmo può richiedere un numero di operazioni
diverse per ingressi di dimensione uguale:
complessità media: complessità valutata su tutti i possibili
ingressi
complessità nel caso peggiore: complessità dell’algoritmo
per l’ingresso che richiede più operazioni
Di solito, quando si parla di complessità, ci si riferisce
alla complessità nel caso peggiore
Fondamenti di Informatica I  a.a. 2008-09
9
Complessità asintotica: array e liste
Array
n: numero degli elementi dell’array
Ricerca/inserimento/cancellazione di un elemento
Complessità O (n)
Liste semplici
n: numero delle posizioni nella lista
Ricerca/cancellazione di un elemento
Complessità O (n)
Inserimento di un elemento all’inizio della lista (in testa)
Complessità O (1)
Fondamenti di Informatica I  a.a. 2008-09
10
Complessità asintotica: alberi binari
Alberi binari di ricerca
n: numero dei nodi dell’albero
Inserire, eliminare o ricercare un elemento in un albero
binario bilanciato
Complessità: O (log2n)
6
3
1
Fondamenti di Informatica I  a.a. 2008-09
4
8
7
9
11
Complessità asintotica: tabelle hash
Problema
Memorizzare in maniera opportuna un insieme di dati 
tipicamente sotto forma di record  in modo da poter
reperire un qualsiasi elemento dell’insieme con un
numero “piccolo” di tentativi
Cosa significa “piccolo” ?
Indipendente (o quasi) dalla dimensione della tabella su cui
si effettua la ricerca, quindi con una complessità in tempo
pari ad O (1)
Fondamenti di Informatica I  a.a. 2008-09
12
Funzioni hash  1
h: K → {0, 1, 2, …, m–1}
K: insieme dei valori distinti che possono essere assunti
dalle chiavi dei record
m: dimensione del vettore in cui si intende memorizzare
la tabella
Ipotesi: K sottoinsieme dei numeri naturali
 Possibile funzione di accesso:
h(k)  k MOD m, kK
Valore della funzione sempre compreso fra 0 e m–1
Fondamenti di Informatica I  a.a. 2008-09
13
Funzioni hash  2
Se K non è un sottoinsieme dei numeri naturali
Esempio: insieme di stringhe alfanumeriche
La funzione hash si applica a numeri
 Per utilizzarla in corrispondenza di una chiave non numerica
occorre associare alla chiave un valore numerico
Necessità di definire funzioni hash generali
Associazione di un valore numerico ad una chiave di
qualunque tipo
Applicazione della funzione hash a tale valore
Esempio: si utilizza la somma dei codici ASCII dei caratteri
che costituiscono la stringa
Fondamenti di Informatica I  a.a. 2008-09
14
Collisioni  1
Associazione, da parte di una trasformazione, della
stessa posizione a chiavi distinte
Sinonimi
Esempio: [10,12,20,23,27,30,31,39,42,44,45,49,53,57,60]
h(chiave)  (chiave MOD 15)
Posizione 0 ← 30, 45, 60
Posizione 8 ← 23, 53
Posizione 12 ← 12, 27, 42, 57
Ciascuna posizione dell’array può contenere al più un
elemento; occorre…
Ridurre al massimo le collisioni
Gestirle quando si verificano
Fondamenti di Informatica I  a.a. 2008-09
15
Collisioni  2
Funzioni di hashing perfetto (che evitano i duplicati) sono
rare, anche per tabelle grandi
Esempio: paradosso del compleanno
Dato un gruppo di 23 persone, ci sono più del 50% di
probabilità che due di esse siano nate nello stesso giorno
dell’anno
 In altre parole, se scegliamo una funzione aleatoria (a valori
casuali) che trasforma 23 chiavi in un indirizzo di una tabella di
365 elementi, la probabilità che due chiavi NON collidano è solo
0.4927 (meno della metà)
Individuare una funzione di accesso che porti ad un numero
ridotto di collisioni è un problema complesso
Fondamenti di Informatica I  a.a. 2008-09
16
Collisioni  3
Tuttavia… numero di collisioni ridotto drasticamente se
accettiamo uno spreco del 25% di memoria extra
0
57
Esempio: array di 19 elementi (indicizzati da 0 a 18) 12 20, 39
Posizione
Posizione
Posizione
Posizione
Posizione
Posizione
Posizione
Posizione
Posizione
Posizione
Posizione
0 ← 57
8 ← 27
1 ← 20, 39
10 ← 10
3 ← 60
11 ← 30, 49
4 ← 23, 42
12 ← 12, 31
6 ← 44
15 ← 53
7 ← 45
60
4
23, 42
5
h(chiave)  (chiave MOD 19)
Collisioni non eliminate del tutto
Fondamenti di Informatica I  a.a. 2008-09
3
6
44
7
45
8
27
9
10
10
11
30, 49
12
12, 31
13
14
15
53
16
17
18
17
Gestione delle collisioni  1
Uso di liste concatenate destinate alla memorizzazione
degli elementi che, in inserimento, hanno portato ad
una collisione
Ricerca di un elemento di chiave k
Si calcola h(k)
Se si verifica una collisione allora si accede alla lista
associata alla posizione h(k) e la si scandisce
Fondamenti di Informatica I  a.a. 2008-09
18
Gestione delle collisioni  2
Il costo dell’operazione di ricerca  realizzata in modo
lineare relativamente alle liste di elementi in collisione 
si mantiene pressoché indipendente da n (numero degli
elementi contenuti nella tabella)
Inserimento/cancellazione costano O (1)
Metodo non adatto a reperire sottoinsiemi di dati con
chiave che soddisfi una data relazione
Fondamenti di Informatica I  a.a. 2008-09
19
Complessità asintotica fattoriale
Sia dato un programma che prende in ingresso i
partecipanti ad una competizione e genera (ad esempio
per stamparle) tutte le possibili classifiche finali
n: numero di partecipanti
Complessità: O (n!)
Si osservi che n! è un numero molto grande anche per
n relativamente piccoli
20!  2.432.902.008.176.640.0002.41018
Fondamenti di Informatica I  a.a. 2008-09
20
Complessità asintotica polinomiale
Sia dato un programma che ha come ingresso due
array a, b e cerca tutte le coppie (i,j) tali che a[i]b[j]
n: dimensione di a
m: dimensione di b
Complessità: O (nm)
void search(int a[], int b[], int alength, int blength)
{…
for(i0;ialength;i){
for(j0;jblength;j){
if(a[i]b[j])
printf(“Trovata corrispondenza: a[%d]b[%d]%d”, i, j, a[i]);
}
}
}
Fondamenti di Informatica I  a.a. 2008-09
21
Algoritmi facili e difficili
In base alla loro complessità temporale asintotica, gli
algoritmi sono tipicamente divisi in classi
Algoritmi a complessità costante O (1) o lineare O (n)
Molto veloci, “scalabili”
Algoritmi a complessità polinomiale O (na) per un qualche
valore a
Usabili se l’esponente a è piccolo
Algoritmi a complessità esponenziale O (an) per un qualche
valore a (1)
Usabili solo per n molto piccoli
Fondamenti di Informatica I  a.a. 2008-09
22
Algoritmi a complessità esponenziale
Fondamentale: perché gli algoritmi a complessità
esponenziale sono considerati quasi inusabili?
Perché richiedono talmente tante
probabilmente anche i calcolatori futuri
grado di eseguire in tempi ragionevoli
implementazioni (programmi) per dati in
dimensionalità
Fondamenti di Informatica I  a.a. 2008-09
operazioni che
non saranno in
le loro possibili
ingresso ad alta
23
Esempio
Si consideri il programma che genera tutte le classifiche
finali di una competizione con n partecipanti,
complessità O (n!) (è esponenziale, perché n! n n )
Con 20 concorrenti le classifiche sono 20! 2.41018
Un computer che generi 1 miliardo di classifiche al secondo,
circa 31016 l’anno, impiegherebbe circa 79 anni per
generare tutte le classifiche richieste
Tendenzialmente, i computer diverranno sempre più veloci e
fra dieci anni forse saranno abbastanza veloci da realizzare in
un mese quello per cui adesso occorrono 79 anni ma…
…comunque, fra dieci anni per risolvere il problema con 21
partecipanti occorreranno ancora 21 mesi e per 25
partecipanti circa 531300 anni!!
Fondamenti di Informatica I  a.a. 2008-09
24
Algoritmi e complessità
Fondamenti di Informatica I  a.a. 2008-09
25
La ricerca dicotomica  1
Per “cercare” un elemento in un vettore ordinato esiste
un metodo detto ricerca binaria o dicotomica
Si confronta il valore val da ricercare con l’elemento
centrale del vettore A[length/2]
Se val è minore dell’elemento mediano, si ripete la ricerca
sulla metà sinistra del vettore, altrimenti si ricerca nella
metà destra
Fondamenti di Informatica I  a.a. 2008-09
26
La ricerca dicotomica  2
Esempio: ricerca del numero 23
Si confronta 23 con 13
0
2
4
5
8
9
13 16 20 23 27 30 34 35
Ci si concentra sulla metà destra (da ind. 8 a ind. 14): si confronta 23 con 27
0
2
4
5
8
9
13 16 20 23 27 30 34 35
Ci si concentra sulla metà sinistra (da ind. 8 a ind. 10): si confronta 23 con 20
0
2
4
5
8
9
13 16 20 23 27 30 34 35
Ci si concentra sulla metà destra (da ind. 9 a ind. 9): trovato!!
0
2
4
Fondamenti di Informatica I  a.a. 2008-09
5
8
9
13 16 20 23 27 30 34 35
27
Implementazione della ricerca dicotomica
int search(int val, int A[], int from, int to)
{
int center(fromto)/2;
if (from  to) return 1;
if (fromto) {
if (A[from]val) {return from;}
return 1;} // si esegue solo se A[from]!val
//si esegue solo se (fromto)
if (valA[center]){ return search(val,A,from,center1);}
if (valA[center]){ return search(val,A,center1,to);}
return center;
}
Fondamenti di Informatica I  a.a. 2008-09
28
Complessità della ricerca dicotomica
La ricerca dicotomica divide il vettore in due ad ogni
passo:
n
dopo p passi la dimensione del vettore è p
2
n
nel caso peggiore, la ricerca si ferma quando p è 1, cioè
2
quando plog2n
Quindi la ricerca dicotomica è O (log2n)
Fondamenti di Informatica I  a.a. 2008-09
29
Mergesort  1
Il Mergesort è un algoritmo basato sul paradigma del
divide et impera
Una strategia divide et impera consiste nel suddividere
un problema in sottoproblemi, nel risolvere i
sottoproblemi, e nel ricomporli per ottenere la soluzione
del problema originale
Il Mergesort è composto da due fasi:
una fase di divisione del vettore da ordinare in sottovettori
una fase di ricomposizione dei risultati (merge)
Fondamenti di Informatica I  a.a. 2008-09
30
Mergesort  2
Idea
Dato un vettore da ordinare, lo si divide in due sottovettori di
ugual dimensione, si ordinano i sottovettori e poi si “fondono”
insieme
6
1
6
1
2
8
2
8
3
4
Divisione
7
5
3
4
2
5
Ordinamento
Ordinamento
1
7
6
8
1
2
Fondamenti di Informatica I  a.a. 2008-09
Fusione
3
4
5
6
3
4
7
8
5
7
31
Mergesort: la divisione ricorsiva
Come si ordinano i due sottovettori ?
Applicando ricorsivamente la divisione fino a quando il vettore
contiene un solo elemento: in tal caso l’ordinamento è banale
6
6
6
6
1
1
2
1
2
Fondamenti di Informatica I  a.a. 2008-09
8
3
4
Divisione
8
2
1
2
8
3
8
3
7
5
3
4
7
4
5
7
4
7
5
5
32
Mergesort: la fusione ricorsiva  1
I sottovettori ordinati verranno poi ricorsivamente fusi
1
2
3
4
5
6
7
8
Fusione
1
1
6
2
6
2
6
1
Fondamenti di Informatica I  a.a. 2008-09
3
8
2
8
3
8
3
4
5
7
4
5
4
7
7
5
33
Mergesort: la fusione ricorsiva  2
La fusione viene realizzata utilizzando due indici che scorrono i
due sottovettori da fondere:
1.
2.
3.
Ad ogni passo si confrontano i due elementi indicati dagli indici i e j,
A[i], A[j]
Si copia l’elemento minore in un vettore d’appoggio e si incrementa
l’indice corrispondente
Si torna al passo 1. fino a quando i due vettori non sono stati
completamente visitati
1
2
6
8
1
i
3
4
5
2
3
4
5
6
7
8
7
k
j
Fondamenti di Informatica I  a.a. 2008-09
34
Complessità del Mergesort
Il Mergesort ha complessità O (nlog2n) sia nel caso
medio che nel caso pessimo
Mergesort è un algoritmo ottimo!
La sua complessità asintotica è la migliore possibile
Comunque…
…esistono algoritmi che per alcuni ingressi fanno meglio di
nlog2n (ad es., Bubblesort su vettori ordinati)
…esistono altri algoritmi con complessità nlog2n nel caso
pessimo  Heapsort
Fondamenti di Informatica I  a.a. 2008-09
35
Quicksort  1
Quicksort, come Mergesort, è un algoritmo divide et
impera
Idea
Si divide il vettore A in due sottovettori, che contengono
rispettivamente tutti gli elementi maggiori e minori di
(per esempio) A[0], cioè il primo elemento del vettore 
detto perno
Si ripete ricorsivamente la divisione…
Fondamenti di Informatica I  a.a. 2008-09
36
Quicksort  2
4
2
1
6
3
8
7
5
Si ripartisce il vettore rispetto ad A[1]  4
3
3
2
2
1
4
6
1
8
7
6
8
Si divide rispetto a 3
1
1
2
3
2
Fondamenti di Informatica I  a.a. 2008-09
7
5
Si divide rispetto a 6
5
5
5
6
7
8
7
8
37
Quicksort: l’operazione perno  1
Come si divide il vettore?
Si usano due indici i, j che
Si scorrono i, j confrontando con 4
4
scorrono il vettore da sinistra
e da destra, rispettivamente
L’indice i scorre fino a quando
A[i]A[1]
L’indice j scorre fino a quando
A[j]A[1]
Si effettua lo scambio fra A[i]
e A[j] e quindi si procede
come sopra
2
8
3
1
7
5
j
i
Si scambiano gli elementi
4
2
8
6
3
i
1
7
5
j
Si scorrono i, j confrontando con 4
4
2
1
i
Fondamenti di Informatica I  a.a. 2008-09
6
6
3
8
7
5
j
38
Quicksort: l’operazione perno  2
Alla fine si scambia il perno con l’elemento in posizione j
Si scambiano gli elementi
4
2
1
6
i
3
8
7
5
j
Si scambia A[j] con il perno
4
2
1
3
6
8
7
5
6
8
7
5
j
3
Fondamenti di Informatica I  a.a. 2008-09
2
1
4
39
Implementazione
void perno(int A[], int from, int to)
{
int ifrom1, jto;
while(ij){
while(A[i]A[from]) i;
while(A[j]A[from]) j;
if(ij) scambia(A,i,j);
}
}
scambia(A,from,j);
Fondamenti di Informatica I  a.a. 2008-09
40
Complessità del Quicksort
Il Quicksort ha complessità media O (nlog n)
Il caso pessimo si verifica quando il perno finisce in
fondo o in testa al vettore
In tal caso, Quicksort ha complessità pari ad O (n2)
Fondamenti di Informatica I  a.a. 2008-09
41
Mergesort vs Quicksort
Mergesort ha il vantaggio di avere complessità sempre
O (nlog n)
Quicksort ha il vantaggio di non richiedere un vettore di
appoggio: ordina il vettore “in loco” (minore
complessità spaziale)
In media, Quicksort si comporta “bene” e, per questo
motivo, in pratica spesso è preferito a Mergesort
Fondamenti di Informatica I  a.a. 2008-09
42
Heap  1
Ospita gli elementi dell’insieme A di cardinalità n, su cui
è definita una relazione d’ordine totale “”
Lo heap (mucchio) è un albero binario
Proprietà 1
L’albero è quasi perfettamente bilanciato
È completo fino al livello k1, cioè contiene il numero massimo di
nodi, 2k1, mentre al livello k contiene un numero di nodi (foglie)
compreso tra 1 e 2k
I nodi a livello massimo sono tutti addossati a sinistra
Proprietà 2
Ogni nodo contiene un elemento  dell’elemento contenuto
nel padre
Fondamenti di Informatica I  a.a. 2008-09
43
Heap  2
Noto il valore di n, la forma
dell’albero è
fissata dalla
Proprietà 1
L’allocazione degli elementi nei
nodi può variare, nel rispetto
della Proprietà 2
L’elemento massimo dell’insieme
è allocato nella radice
Nello heap, i sottoalberi di
ciascun nodo sono ancora heap
Lo heap può essere allocato in
un array
Fondamenti di Informatica I  a.a. 2008-09
63
38
12 28
10
5
23
17 22
18
1
2
3
4
5
6
7
8
9
10
63
38
23
12
28
17
22
10
5
18
44
Heap  3
Con l’allocazione lineare…
A[1] è l’elemento contenuto nella radice dello heap
Per ogni A[i], gli elementi corrispondenti ai figli sinistro e
destro, se esistono, sono memorizzati in A[2i] e A[2i1]
Se 2in e/o 2i1n il figlio sinistro e/o destro di A[i] non
esiste nell’albero
A[2i]A[i] e A[2i1]A[i], quando tali elementi sono definiti
Fondamenti di Informatica I  a.a. 2008-09
45
Heapsort  1
Lo heap trova la sua applicazione più elegante nel
metodo di ordinamento noto come Heapsort
Si estrae l’elemento massimo dallo heap (quello nella
radice, o in prima posizione nella rappresentazione lineare)
Si ricostruisce lo heap
…fino a quando non ci sono più elementi nello heap
(ovvero gli elementi del vettore sono ordinati)
Fondamenti di Informatica I  a.a. 2008-09
46
Heapsort  2
Come si ricostruisce lo heap, dopo l’estrazione della
radice?
18
63
38
12 28
10
5
38
23
23
12 28
17 22
10
18
17 22
5
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
63
38
23
12
28
17
22
10
5
18
18
38
23
12
28
17
22
10
5
63
Fondamenti di Informatica I  a.a. 2008-09
Continua…
47
Heapsort  3
Si considera il massimo fra i due figli della radice e, se
max{A[2],A[3]}A[1], si effettua lo scambio
38
18
Si scambia A[1] con A[2]
38
12 28
10
18
23
23
12 28
17 22
10
5
17 22
5
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
18
38
23
12
28
17
22
10
5
63
38
18
23
12
28
17
22
10
5
63
Fondamenti di Informatica I  a.a. 2008-09
Continua…
48
Heapsort  4
Si considera il massimo fra i due figli di A[2] e, se
max{A[4],A[5]}A[2], si effettua lo scambio
38
38
Si scambia A[2] con A[5]
18
12 28
10
28
23
23
12 18
17 22
10
5
17 22
5
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
38
18
23
12
28
17
22
10
5
63
38
28
23
12
18
17
22
10
5
63
Fondamenti di Informatica I  a.a. 2008-09
Continua…
49
Heapsort  5
Si estrae A[1] che è l’elemento più grande… e si ricomincia
il procedimento di ricostruzione
5
38
28
12 18
10
28
23
23
12 18
17 22
17 22
10
5
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
38
28
23
12
18
17
22
10
5
63
5
28
23
12
18
17
22
10
38
63
Fondamenti di Informatica I  a.a. 2008-09
50
Heapsort  6
Poiché ogni estrazione e ricostituzione dello heap
richiede tempo O (log2n'), se n′ è il numero di elementi
attualmente contenuti nello heap…
Heapsort ha complessità O (nlog2n)
L’algoritmo di ordinamento può essere realizzato
facilmente sulla “rappresentazione sequenziale” dello
heap
Fondamenti di Informatica I  a.a. 2008-09
51
Heapsort  7
void heapsort(int a[], int left, int right)
{
int k, temp, sizerightleft1, *paleft1;
/* si costruisce lo heap */
for (ksize2; k1; k)
heap(p, k, size);
/* si scambia l’elemento più grande con quello finale
* e si ricostruisce lo heap
*/
while (size1)
{
temp  p[1];
p[1]  p[size];
p[size]  temp;
heap(p, 1, size);
}
exit(0);
}
Fondamenti di Informatica I  a.a. 2008-09
52
Heapsort  8
/* Costruzione topdown di uno heap */
#define LESS(A,B)((A)(B))
void heap(int a[], int k, int size)
{
int j, temp;
while (2ksize)
{
j  2k;
if (jsize && LESS(a[j],a[j1]))
j;
if (!LESS(a[k],a[j]))
break;
temp  a[k];
a[k]  a[j];
a[j]  temp;
k  j;
}
}
Fondamenti di Informatica I  a.a. 2008-09
53
Ancora sulla complessità
Fondamenti di Informatica I  a.a. 2008-09
54
Problemi e algoritmi
Anche per i problemi si parla di complessità
Tipicamente non si riesce a definire univocamente la
complessità di un problema, perché...
...lo stesso problema può essere risolto con algoritmi
diversi che hanno diversa complessità
…anche se si riesce a stabilire qual è il miglior algoritmo
per la risoluzione di un dato problema, tale stima ha
comunque un valore non assoluto, ma limitato nel tempo,
in quanto non è dato prevedere se in futuro potrà esistere
un metodo risolutivo migliore
Per questi motivi, si parla solo di limite inferiore e
superiore alla complessità di un problema
Fondamenti di Informatica I  a.a. 2008-09
55
Complessità di un problema
In alcuni casi è possibile dimostrare che nessun
algoritmo che risolve un dato problema può/potrà
impiegare meno risorse di un certo limite inferiore
Esempi banali
Nessun algoritmo che genera tutte le classifiche possibili
per n concorrenti può farlo in meno di n! operazioni (il
limite inferiore alla complessità è O (n!))
Nessun algoritmo può effettuare la somma fra vettori
ndimensionali in meno di n operazioni (il limite inferiore
alla complessità è O (n))
Esempio non banale
Nessun algoritmo può ordinare un vettore di n elementi in
meno di nlog2n operazioni, nel caso peggiore
Fondamenti di Informatica I  a.a. 2008-09
56
Algoritmi ottimi
Un algoritmo si dice ottimo, quando ha complessità pari
al limite inferiore
Esempi
Mergesort e Heapsort sono ottimi
Si consideri il problema di sommare gli elementi di un vettore:
un algoritmo che scorre tutti gli elementi e li somma uno ad uno
richiede O (n) operazioni: tale algoritmo è ottimo perché la sua
complessità corrisponde con quella minima
Si consideri il problema di inserire un elemento in un albero
binario bilanciato che contiene n elementi:
Abbiamo visto una soluzione algoritmica che impone O (log2n)
operazioni  log2n è un limite superiore per tale problema
Si può dimostrare che tale complessità corrisponde con il limite
inferiore e che l’algoritmo proposto è ottimo
Fondamenti di Informatica I  a.a. 2008-09
57
Algoritmi e computer
Dubbi:
La complessità è indipendente dal computer su cui “gira” il
programma?
Ad esempio, se si inventasse un calcolatore in grado di generare
contemporaneamente tutte le classifiche di n concorrenti, allora
quel problema non avrebbe più complessità n!
Oppure… potrebbe esistere in futuro un computer in grado di
ordinare un vettore di qualsiasi lunghezza per mezzo di una sola
istruzione
Nessuno conosce la risposta ma, fino ad ora, nessuno è
riuscito a progettare un computer con queste capacità
Tutti i calcolatori conosciuti sono equivalenti, in termini
di capacità di calcolo, ad un computer semplicissimo: la
macchina di Turing
Fondamenti di Informatica I  a.a. 2008-09
58
La macchina di Turing
Alan Turing (19121954) è considerato uno dei padri
dell’informatica
Nel 1936 propose l’idea di una macchina immaginaria
che fosse capace di eseguire ogni tipo di calcolo su
numeri e simboli
Esistono varie versioni della macchina di Turing, quella
più simile ai nostri calcolatori è quella cosiddetta a
registri
Fondamenti di Informatica I  a.a. 2008-09
59
La macchina di Turing a registri
È costituita da un insieme di registri di lavoro R1, R2, R3,… e
di registri di ingresso I1, I2, I3,…
Ogni registro è una cella di memoria che contiene un intero non
negativo
I programmi sono costituiti da tre semplici tipi di istruzioni:
incremento: Ri 
Il registro i viene incrementato di 1
decremento: Ri 
Il registro i viene decrementato di 1; se
il registro ha già valore 0, l’istruzione
non ha effetto
salto condizionato: IF Ri GOTO L1
Se il registro i contiene un valore
maggiore di 0, si va all’istruzione L1
Fondamenti di Informatica I  a.a. 2008-09
IF I1 GOTO ciclo
ciclo:
I2
I1
IF I1 GOTO ciclo
fine:
Programma che somma i
contenuti di I1 e I2 in I2
60
La tesi di ChurchTuring
La tesi di ChurchTuring afferma che:
Ogni problema intuitivamente calcolabile (risolubile) da
un qualsiasi elaboratore è calcolabile da una macchina
di Turing, purché dotata di memoria (e tempo di
elaborazione) sufficiente
Nessuno è mai
ChurchTuring
riuscito
a
confutare la
tesi
di
La maggior parte dei ricercatori ritiene che sia vera
Fondamenti di Informatica I  a.a. 2008-09
61
Il problema della terminazione
Supponiamo che esista un programma halt in grado di
risolvere i problema della terminazione
halt(P,I) restituisce:
true se P con ingresso I termina
false se P con ingresso I non termina
Consideriamo il programma Q
Cosa succede se si applica Q a Q ?
Q(Q) termina o no ?
void Q(Program P){
while (halt(P,P)) {}
}
Se Q(Q) termina allora halt(Q,Q) dovrebbe essere vero… ma
allora Q(Q) non dovrebbe terminare
Se Q(Q) non termina allora halt(Q,Q) dovrebbe essere falso
… ma allora Q(Q) dovrebbe terminare
Quindi il programma halt non esiste!!
Fondamenti di Informatica I  a.a. 2008-09
62
Problemi impossibili
Esistono problemi molto difficili… problemi non
calcolabili con una macchina di Turing e  se la tesi di
ChurchTuring è vera  con nessun calcolatore!!
Esempi
Problema della terminazione
Dato un programma e un suo ingresso, dire se il
programma terminerà (o entrerà in un ciclo indefinito)
Problema di Post
Dato un programma e due stati (uno stato è
definito da un certo valore delle variabili), dire se a
partire dal primo stato si potrà raggiungere il secondo
Fondamenti di Informatica I  a.a. 2008-09
63
La macchina non deterministica  1
R4
Nella macchina non deterministica, i
programmi includono anche altre
istruzioni
scelta casuale: FORK
prende in ingresso un insieme di
istruzioni e ne esegue una a caso
istruzione di accettazione: ACCEPT
quando viene eseguita, il programma
termina correttamente
Un problema è risolubile se esiste
un programma e una scelta casuale
per cui il programma termina con
ACCEPT e fornisce la risposta
desiderata
Fondamenti di Informatica I  a.a. 2008-09
cont:
ok:
no:
FORK{ R1,
R1 }
FORK{ R2,
R2 }
IF R1 GOTO cont
IF R4 GOTO no
IF R2 GOTO ok
IF R4 GOTO no
ACCEPT
Programma che assegna a
caso valori in {0, 1} a R1 e R2
e termina solo se R1R21
64
La macchina non deterministica  2
La macchina non deterministica “non calcola più di quella
deterministica”
Si può dimostrare che tutto ciò che è calcolabile sulla macchina
di Turing non deterministica è calcolabile anche sulla macchina
deterministica
Si pensa però che la macchina non deterministica sia più
efficiente di quella deterministica
Il non determinismo può essere pensato come una forma di
parallelismo:
FORK è un istruzione che genera più programmi paralleli
Il parallelismo permette di risolvere i problemi velocemente:
ad esempio, si può cercare un elemento in un vettore
guardando contemporaneamente a tutte le posizioni del
vettore
Fondamenti di Informatica I  a.a. 2008-09
65
Problemi P e NP
I problemi decisionali richiedono solo una risposta
binaria (sì/no), correlata in genere all’esistenza di una
soluzione (es., problema della terminazione)
Nella teoria della complessità, i problemi decisionali si
dividono in due classi
P  problemi risolubili in tempo polinomiale sulla
macchina di Turing deterministica
NP  problemi risolubili in tempo polinomiale sulla
macchina di Turing non deterministica
Includono sia i problemi “facili”, sia anche la quasi totalità
dei problemi che si incontrano nelle situazioni pratiche
Ovviamente vale PNP, ma non è noto se P≠NP
Fondamenti di Informatica I  a.a. 2008-09
66
Problemi NPcompleti  1
Problema decisionale della soddisfattibilità: Data una
forma normale congiuntiva F(x1,x2,…,xn) stabilire se
esiste un assegnamento di valori delle variabili booleane
x1, x2,…, xn che soddisfi F
Qualunque problema della classe NP si riduce, in tempo
polinomiale, al problema della soddisfattibilità PS
PS è il “più difficile” fra i problemi di NP
Fondamenti di Informatica I  a.a. 2008-09
67
Problemi NPcompleti  2
Un problema P è detto NPcompleto se PNP e PS si
riduce a P
I problemi NPcompleti sono tutti equivalenti fra loro:
Sarebbe sufficiente trovare un algoritmo polinomiale per
uno solo di essi ed avremmo trovato un algoritmo
polinomiale per risolvere tutti i problemi
Inoltre, tutti i problemi in NP sarebbero risolubili in tempo
polinomiale sulla macchina di Turing deterministica, cioè
avremmo dimostrato che NPP!
Fondamenti di Informatica I  a.a. 2008-09
68
Problemi NPcompleti: esempi
Problema decisionale del commesso viaggiatore
Dato un insieme di n città con le relative distanze,
trovare, se esiste, un cammino di lunghezza k che,
partendo da una città, le visiti tutte tornando in quella
di partenza
Un problema NParduo (non decisionale)
Programmazione lineare intera
Data una matrice A e due vettori b, c, calcolare un
vettore di interi x che soddisfi Axb e minimizzi f(x)cx
Problemi di programmazione lineare
definire l’orario dei treni e degli autobus
definire l’orario delle lezioni
…
Fondamenti di Informatica I  a.a. 2008-09
69
Conclusioni: PNP e tesi di Church
Attualmente si pensa che NPP
…ma nessuno è ancora riuscito a dimostrarlo
Si pensa anche che la tesi di Church sia vera:
ovviamente questo non si può dimostrare ma è,
eventualmente, solo confutabile
Talvolta, problemi con complessità proibitiva sono utili:
Ad esempio, gli algoritmi crittografici sono basati sul fatto
che “decrittare” una chiave è molto complesso e
richiederebbe un tempo troppo lungo
Se la tesi di Church non fosse vera o se PNP, tali metodi
non sarebbero più efficaci
Fondamenti di Informatica I  a.a. 2008-09
70