Di cosa parliamo oggi?
Oggi parliamo di Analisi di Algoritmi
Analisi di Algoritmi = valutazione delle risorse usate da
algoritmi per risolvere un dato problema
Risorse =
Tempo impiegato dall’algoritmo
Memoria usata dall’algoritmo
Tipicamente analizzeremo gli algoritmi in termini del
tempo di esecuzione da loro impiegato per produrre
l’output richiesto.
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 1/29
In pratica, il tempo di esecuzione dipende (anche) dall’implementazione
Schema di Implementazione di Algoritmi
Algoritmo
↓
Programmatore
↓
Programma
↓
Compilatore
↓
Eseguibile
↓
Calcolatore
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 2/29
Il tempo di esecuzione dipende quindi...
Dall’abilitá del programmatore e dal linguaggio di
programmazione usato
Dal linguaggio macchina del computer
Dal codice che il compilatore genera
Dalla taglia del problema (=la “dimensione" dell’ input)
Da come é fatto l’input (ad es., ordinato/non-ordinato)
Dal numero di operazioni elementari eseguite
dall’algoritmo
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 3/29
Quindi...
Quantificheremo le risorse usate da un algoritmo a
meno di una costante moltiplicativa (useremo quindi le
notazioni asintotiche O, Θ e Ω).
Perché?
Perché le costanti moltiplicative dipendenti dai primi 3
aspetti prima enunciati non sono a priori quantificabili,
in quanto dipendono da aspetti a noi ignoti
Inoltre, per input molto grandi (il che corrisponde a
situazioni pratiche) l’influenza che tali costanti hanno sul
“reale” tempo di esecuzione di un algoritmo é minore
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 4/29
Operazioni elementari
Misureremo la complessitá di un algoritmo in termini del
numero di operazioni elementari usate
Esempi di operazioni elementari: addizione e
moltiplicazione di numeri (se piccoli...), confronto tra
elementi, seguire un puntatore...
Si assume che le operazioni elementari richiedano un
tempo costante per la loro esecuzione (=una unitá di
tempo)
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 5/29
La taglia dell’input
Il tempo di esecuzione di un algoritmo in generale dipende
quanto grande é l’input (taglia dell’input). Ma cosa
intendiamo esattamente per taglia dell’input?
Criterio di costo logaritmico: la taglia dell’input é il
numero di bits necessari per rappresentarlo
Criterio di costo uniforme: la taglia dell’input é il numero
di "elementi" che lo costituiscono
Nell’ipotesi che ogni istruzione del computer richieda
un’unitá di tempo e che un numero o "elemento"
richieda una parola di memoria, le due misure
coincidono a meno di una costante moltiplicativa
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 6/29
Esempi
Problema
taglia dell’input
operazione elementare
Trovare x in una lista
# di elementi della lista
confronto tra elementi
Moltiplicazione di matrici
dimensione delle matrici
moltiplicazione di due numeri
Ordinamento di un array
# di elementi dell’array
confronto tra elementi
Visita di un albero/grafo
#numero di nodi/archi
seguire un puntatore
Moltiplicazione di due numeri
# bits per rappresentarli
addizione/sottrazione
Nell’ultimo caso della moltiplicazione di due numeri abbiamo usato il
criterio di costo logaritmico per misurare la taglia dell’input, nei primi
quattro casi abbiamo usato il criterio di costo uniforme.
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 7/29
Anche la forma dell’input influenza la complessitá
La complessitá di un algoritmo puó dipendere anche da come
é fatto l’input (ad es., ordinare n elementi puó essere fatto piú
velocemente se essi sono giá (quasi) ordinati)
Useremo come strumento di analisi il caso peggiore: il tempo
usato dall’algoritmo nella situazione piú "sfavorevole" in input.
La complessitá di tempo di un algoritmo A, su di un input di
taglia n, che denoteremo con T (n) sará quindi
T (n) = il massimo tempo richiesto da A, dove il massimo é
calcolato su tutti i possibili input di taglia n
Ció ci dará un limite superiore alla complessitá dell’algoritmo,
su tutti i possibili input (nel senso che A non
richiederá mai tempo superiore a T (n) su di un input di taglia n.
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 8/29
Quindi, ad esempio, se diciamo che....
la complessitá T (n) di un algoritmo A é O(n2 ), vuol dire che A non
richiede mai tempo superiore a cn2 , per produrre il suo output, per c
opportuna e n sufficientemente grande.
la complessitá T (n) di un algoritmo A é Ω(n2 ), vuol dire che A
richiede almeno tempo cn2 , per produrre il suo output nel caso
peggiore, per c opportuna e n sufficientemente
Quindi NON si intende dire che A impiega tempo cn2 , su ogni input di
taglia n, ma nel secondo caso si intende che ESISTE almeno un
input di taglia n (n suff. grande) su cui A richiede tempo cn2 (e nel
primo caso si intende che NON esistono input per cui l’algoritmo
richiede tempo > cn2 ).
(Ad es., la ricerca sequenziale di un elemento x in una lista richiede
O(n) e Ω(n) nel caso peggiore, ma se x é il primo elemento della
lista, richiede O(1))
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 9/29
Esempio
A LG(n)
1. if n é pari
2.
then return(0)
3.
else
4.
for i = 1 to n do
5.
x=x+1
La complessitá dell’algoritmo nel caso peggiore é Θ(n).
Possiamo dire che l’algoritmo esegue Θ(n) passi per ogni input?
No! Infatti esise un numero infinito di input su cui l’algoritmo esegue
un solo passo.
Ció che possiamo dire é che l’algoritmo non esegue mai piú di O(n)
passi per ogni input, e che esegue almeno n passi per certi input.
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 10/29
Calcolo della complessitá di tempo
Effettueremo quasi esclusivamente analisi nel caso
peggiore, usando le seguenti regole:
il costo di istruzioni semplici, quali assegnazione,
letture/scrittura di variabili é O(1)
il costo di istruzioni tipo if.... then ....else é pari al tempo
per effettuare il test (tipicamente O(1)) piú
O(costo della alternativa piú costosa)
il costo di loop (for, while, repeat) é pari alla somma su
tutte le iterazioni del costo di ogni iterazioni
Usando queste regole si puó ottenere la complessitá di
tempo di ogni algoritmo (ad eccezione degli algoritmi
ricorsivi, che richiedono una tecnica diversa)
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 11/29
Un pó di preliminari
Quant’é
k
X
i?
i=1
Valutiamo 2
2
k
X
i =
Pk
i=1
i:
1 +
2
+
3
+ . . . + (k − 1) +
k
i=1
+k +
(k − 1) + (k − 2) + . . . +
2
+
1
= (k + 1) + (k + 1) + (k + 1) + . . . + (k + 1) + (k + 1)
= k(k + 1)
da cui
k
X
i=1
k(k + 1)
i=
2
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 12/29
Esercizi
Usando la notazione Θ, stimare il numero di volte che la istruzione
x = x + 1 viene eseguita:
1.
for i = 1 to 2n
x=x+1
Θ(n)
2.
for i = 1 to 2n
for j = 1 to n
x=x+1
Θ(n2 )
3.
for i = 1 to n
for j = 1 to i
for k = 1 to j
x=x+1
Pn
i=1
Pi
j=1
j =
Pn
i(i+1)
i=1
2
=
Pn
2
Θ(i
)
i=1
= Θ(n3 )
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 13/29
Esercizi
4.
i=n
while i ≥ 1 do
x = x + 1, i = i/2
dopo che il while é eseguito k volte, l’indice i vale n/2k , pertanto il ciclo
viene eseguito t volte, dove t é tale che n/2t = 1, da cui la complessitá
dell’algoritmo é
Θ(log n)
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 14/29
Esercizi
5.
6.
7.
j=n
while j ≥ 1 do
for i = 1 to j
x = x + 1,
j = j/3
i=n
while i ≥ 1 do
for j = 1 to n
x = x + 1,
i = i/2
i=2
while i < n do
i=i∗i
x=x+1
n +n/3 +n/32 . . . + n/3log3 n
Plog3 n
= n i=0 (1/3)i = Θ(n)
Θ(n log n)
Θ(log log n)
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 15/29
Esercizi
Alg(A[1...n])
1. for i = 1 to n do
2.
B[i] = A[i]
3. for i = 1 to n do
4.
j=n
5.
while j > i do
6.
B[i] = B[i] + A[i], j = j − 1
7. for i = 1 to n do
8.
t = t + B[i]
Analisi: Le linee 1. e 2. prendono tempo Θ(n). Le linee da 3. a 6.
prendono tempo n + n − 1 + . . . + 1 = Θ(n2 ). Le linee 7. e 8. prendono
tempo Θ(n). In totale, la complessitá dell’algoritmo é
T (n) = Θ(n) + Θ(n2 ) + Θ(n) = Θ(n2 )
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 16/29
Esercizi
P ROCEDURA(A[1...n], k]
s=0
for i = 1 to k do
s = s + A[i]
s = s/k
M AIN(AA[1...m])
i=m
while i ≥ 1 do
P ROCEDURA(A[1...m], i]
i=i−2
Analisi: La complessitá dell’algoritmo M AIN é
Θ(m) +Θ(m − 2) +Θ(m − 4) + . . . + Θ(1) = Θ(m2 )
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 17/29
Esempio: moltiplicazione di numeri interi
multiply(y, z)
x←0
while z > 0 do
if z é dispari then x ← x + y
y ← 2y; z ← ⌊z/2⌋
return(x)
function
1.
2.
3.
4.
5.
Supponiamo che x e y siano numeri di n bits. Le
istruzioni 1, 3, e 4 costano O(1) ciascuna
Il loop while costa O(n) (viene eseguito al piú n volte, ed
ogni esecuzione costa O(1))
In totale, la complessitá dell’algoritmo é quindi O(n)
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 18/29
Esempio: Bubblesort
Bubblesort(A[1 . . . n])
1.
for i = 1 to n − 1 do
2.
for j = 1 to n − i do
3.
if A[j] > A[j + 1] then
4.
scambia A[j] con A[j + 1]
La 4 costa O(1). La istruzione if . . . then sulle linee 3 e 4
costa O(1). Il loop for sulle linee 2-4 costa O(n − i). Il loop
Pn−1
for sulle linee 1-4 costa O( i=1 (n − i)), con
!
!
n−1
n−1
X
X
i
(n − i) = O n(n − 1) −
O
i=1
i=1
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 19/29
Esempio: Bubblesort
Riassumendo, Bubblesort ha complessitá
!
!
n−1
n−1
X
X
i
(n − i)
= O n(n − 1) −
O
i=1
i=1
n(n − 1)
= O n(n − 1) −
2
= O(n2 )
nel caso peggiore.
Allo stesso modo si puó anche provare che nel caso
peggiore Bubblesort ha complessitá Θ(n2 ).
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 20/29
Utile regola
Piuttosto che procedere con l’analizzare gli algoritmi
istruzione per istruzione, conviene
identificare la operazione fondamentale usata
nell’algoritmo (ovvero quella operazione eseguita almeno
tante volte quanto ogni altra operazione) e osservare che
il tempo di esecuzione é una costante multipla del
numero di operazioni fondamentali usate
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 21/29
Esempio
Nel caso del Bubblesort
Bubblesort(A[1 . . . n])
1.
for i = 1 to n − 1 do
2.
for j = 1 to n − i do
3.
if A[j] > A[j + 1] then
4.
scambia A[j] con A[j + 1]
la operazione fondamentale é chiaramente il confronto eseguito al
Pn−1
passo 3. Esso viene eseguito i=1 (n − i) volte.
Pertanto la complessitá di Bubblesort nel caso peggiore é
O
n−1
X
i=1
(n − i)
!
= O n(n − 1) −
n−1
X
i=1
!
i
n(n − 1)
= O n(n − 1) −
2
= O(n2 )
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 22/29
Altro Esempio: Selection Sort
SelectionSort(A[1 . . . n])
1.
for i = 1 to n − 1 do
2.
minj = 1; minx = A[i]
3.
for j = i + 1 to n do
4.
if T [j] < minx then minj = j; minx = T [j]
5.
T [minj] = T [j]; T [i] = minx
la operazione fondamentale é chiaramente il confronto eseguito al passo
4. Esso viene eseguito
n−1
X
n
X
1
=
i=1 j=i+1
n−1
X
(n − i) = (n − 1) + (n − 2) + . . . 2 + 1
i=1
=
n−1
X
k = n(n − 1)/2 volte
k=1
Pertanto la complessitá di SelectionSort nel caso peggiore é O(n2 )
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 23/29
Altro Esempio: Insertion Sort
InsertionSort(A[1 . . . n])
1.
for i = 2 to n do
2.
x = T [i]; j = i − 1
3.
while j > 0 and x < T [j] do T [j + 1] = T [j], j = j − 1
4.
T [j + 1] = x
Calcoliamo quante volte la condizione del while é testata.
Fissato i, il caso peggiore é quando x é sempre minore di T [j],
∀j ≤ i − 1. In tal caso la condizione é testata i volte.
Pn
In totale il test é effettuato i=2 i = n(n + 1)/2 − 1 = Θ(n2 ) volte, nel
caso peggiore. Da cui si ha che InsertionSort ha complessitá Θ(n2 )
nel caso peggiore.
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 24/29
Esercizi
Consideriamo il seguente programma
P ROGRAMMA (n)
i = 1; r = 0
while i ≤ n do
for j = 1 to n − i do
r =r+i
i=i∗2
Valutiamo la sua complessità in termini della notazione Θ ed in funzione
di n.
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 25/29
Sia T (n) la complessitá del programma:
P ROGRAMMA (n)
i = 1; r = 0
while i ≤ n do
for j = 1 to n − i do
r =r+i
i=i∗2
T (n)
=
(n − 1) + (n − 2) + (n − 4) + . . . + (n − 2⌊log n⌋ )
⌊log n⌋
=
n(⌊log n⌋ + 1) −
X
i=0
2⌊log n⌋+1 − 1
2 = n(⌊log n⌋ + 1) −
2−1
i
⇒ n(⌊log n⌋ + 1) − 2n ≤ T (n) ≤ n(⌊log n⌋ + 1) − n
ovvero
T (n) = Θ(n log n)
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 26/29
Valutazione di progressioni geometriche
Somme finite: Sia Sn =
Pn
i . Se α 6= 1 allora
α
i=0
Sn (α − 1) = α · Sn − Sn =
n
X
αi+1 −
i=0
= α + α2 + . . . + +αn + α
n
X
αi
i=0
n+1
− 1 − α − α2 − . . . − αn
= αn+1 − 1
da cui Sn = (αn+1 − 1)/(α − 1).
Somme infinite: Supponiamo 0 < α < 1 e sia S =
Allora αS =
P∞
i=1 α
i,
S(1 − α) = S − αS =
da cui
∞
X
i=0
αi −
∞
X
P∞
i.
α
i=0
αi = α0 = 1, ovvero S = 1/(1 − α)
i=1
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 27/29
Valutazione di progressioni geometriche
Applicando quindi la formula
Sn =
n
X
i=0
αn+1 − 1
α =
α−1
i
alla precedente espressione
⌊log n⌋
X
2i
i=0
otteniamo
⌊log n⌋
X
i=0
⌊log n⌋+1 − 1
2
2i =
2−1
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 28/29
Valutazione di progressioni geometriche
Per quanto riguarda la espressione
P⌊log3 n⌋ 1 i P∞ 1 i
che i=0
< i=0 3
3
Applicando quindi la formula
Sn =
∞
X
P⌊log3 n⌋
i=0
αi =
i=0
(1/3)i ovviamente vale
1
1−α
alla espressione
∞ i
X
1
3
i=0
otteniamo
⌊log3 n⌋ X
i=0
1
3
i
<
∞ i
X
1
i=0
3
1
=
= (3/2)
1 − (1/3)
Universitá degli Studi di Salerno – Corso di Algoritmi – Prof. Ugo Vaccaro – Anno Acc. 2009/10 – p. 29/29