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