Quicksort Moltiplicazione di interi Master Theorem ... · Introduzione agli algoritmi, o ad altri...
Transcript of Quicksort Moltiplicazione di interi Master Theorem ... · Introduzione agli algoritmi, o ad altri...
Quicksort
Moltiplicazione di interi
Master Theorem
Valutazione del tempo di esecuzione di
algoritmi iterativi e ricorsivi
Algoritmi basati sulla tecnica Divide et Impera
In questo corso:
• Ricerca binaria
• Mergesort (ordinamento)
• Quicksort (ordinamento)
• Moltiplicazione di interi
• Moltiplicazione di matrici (non in programma)
NOTA: nonostante la tecnica Divide et impera sembri così «semplice»
ben due «top ten algorithms of the 20° century» sono basati su di essa:
Fast Fourier Transform (FFT)
Quicksort
Applicazioni:
• Ordinare alfabeticamente lista di nomi, o insieme di numeri, o insieme
di compiti d’esame in base a cognome studente
• Velocizzare altre operazioni (per es. è possibile effettuare ricerche in
array ordinati in tempo O(log n) )
• Subroutine di molti algoritmi (per es. greedy)
• ….
Ordinamento
INPUT: un insieme di n oggetti a1, a2, …, an
presi da un dominio totalmente ordinato secondo ≤
OUTPUT: una permutazione degli oggetti a’1, a’2, …, a’n tale che
a’1 ≤ a’2 ≤ … ≤ a’n
Algoritmi per l’ordinamento
Data l’importanza, esistono svariati algoritmi di ordinamento,
basati su tecniche diverse:
Insertionsort
Selectionsort
Heapsort
Mergesort
Quicksort
Bubblesort
Countingsort
…..
Ognuno con i suoi aspetti positivi e negativi.
Il Mergesort e il Quicksort sono entrambi basati sulla
tecnica Divide et Impera, ma risultano avere differenti prestazioni
Mergesort (ripasso)
Dato un array di n elementi
I ) Divide: trova l’indice della posizione centrale e divide
l’array in due parti ciascuna con n/2 elementi
(più precisamente n/2 e n/2 )
II) Risolve i due sottoproblemi ricorsivamente
III) Impera: fonde i due sotto-array ordinati usando la
procedura Merge
T(n) = (1) + 2T(n/2) + (n)
La soluzione è T(n) = (n log n)
Nota: sul libro di testo trovate solo una versione randomizzata (cap. 13). Potete fare riferimento al libro di Cormen, Leiserson, Rivest, (Stein) Introduzione agli algoritmi, o ad altri testi consigliati.
Quicksort
Quicksort
Dato un array di n elementi
I ) Divide: scegli un elemento x dell’array (detto “pivot” o perno) e partiziona la
sequenza in elementi ≤ x ed elementi x
II) Risolvi i due sottoproblemi ricorsivamente
III) Impera: restituisci la concatenazione dei due sotto-array ordinati
x=5
3 3 2 1 4 6 5 7
1 2 3 3 4 5 6 7
5 3 2 6 4 1 3 7
1 2 3 3 4 5 6 7
Scelta del pivot
L’algoritmo funziona per qualsiasi scelta (primo / ultimo / …),
ma se vogliamo algoritmo “deterministico” devo fissare la scelta;
nel seguito sceglieremo il primo.
Altrimenti: scelgo “random” e avrò “algoritmi randomizzati”
(vedi Kleinberg & Tardos, cap. 13)
Partizionamento
Partiziona l’array in elementi ≤ x ed elementi x
Però:
1) avrei bisogno di array ausiliari
2) di che dimensione? I due sotto-array hanno un numero variabile di
elementi
Banalmente:
scorro l’array da 1 ad n e inserisco gli elementi ≤ pivot in un
nuovo array e quelli del pivot in un altro nuovo array
Partizione “in loco”
Partition:
• pivot = A[1]
• Scorri l’array da destra verso sinistra (con un indice j) e da sinistra verso
destra (con un indice i) :
da destra verso sinistra, ci si ferma su un elemento ≤ del pivot
da sinistra verso destra, ci si ferma su un elemento ≥ del pivot;
• Scambia gli elementi
• Riprendi la scansione finché i e j si incrociano
Partition (A, p, r)
x = A[p]
i = p-1
j = r+1
while True
do repeat j=j-1 until A[j]≤ x
repeat i=i+1 until A[i]≥ x
if i < j
then scambia A[i] ↔ A[j]
else return j
Partition (Hoare 1962)
Esiste un diverso
algoritmo per il
partizionamento
dovuto a N. Lomuto
ed esistono piccole
varianti di questo (che
potreste incontrare
cambiando libro di testo)
Attenzione: repeat op until cond
significa che: eseguo op; se cond è verificata esco, altrimenti ripeto.
j si ferma su un elemento ≤ x; i si ferma su un elemento ≥ x.
5 3 2 6 4 1 3 7
Partizione in loco: un esempio
5 3 2 6 4 1 3 7
3 3 2 6 4 1 5 7
3 3 2 6 4 1 5 7
3 3 2 1 4 6 5 7
i j
j
j
j
j
i
i
i
i
Scambia 3 con 5
Scambia 1 con 6
≤ 5 5
Restituisce q = j
pivot = 5
3 3 2 1 4 6 5 7
i j
Restituisce q = j. Gli elementi < x
staranno a sinistra; gli elementi >
x a destra; quelli = x possono
stare sia a sinistra che a destra.
Restituisce q = j. Gli elementi < x
staranno a sinistra; gli elementi >
x a destra; quelli = x possono
stare sia a sinistra che a destra.
5 3 2 6 4 1 5 7
5 3 2 6 4 1 5 7
5 3 2 6 4 1 5 7
5 3 2 6 4 1 5 7
5 3 2 1 4 6 5 7
i j
j
j
j
j
i
i
i
i
Scambia 5 con 5
Scambia 1 con 6
≤ 5 5
pivot = 5
5 3 2 1 4 6 5 7
i j
Partition: un altro esempio
5 5 5 5 5 5 5 5
Partition su un array di elementi tutti uguali
5 5 5 5 5 5 5 5
i j
j
j
i
i
Scambia 5 con 5
≤ 5 5
Restituisce q = j
pivot = 5
i
5 5 5 5 5 5 5 5
j i
Scambia 5 con 5 5 5 5 5 5 5 5 5
j
Scambia 5 con 5
5 5 5 5 5 5 5 5
5 5 5 5 5 5 5 5
j i
Scambia 5 con 5
Correttezza di Partition
Perché funziona?
Ad ogni iterazione (quando raggiungo il while):
la “parte verde” di sinistra (da p ad i) contiene elementi ≤ 5;
la “parte verde” di destra (da j a r) contiene elementi 5.
Tale affermazione è vera all’inizio e si mantiene vera ad ogni iterazione
(per induzione)
Nota: Partition restituisce q p: al massimo j si ferma sul primo
elemento, che è ≤ pivot.
Analisi Partition
Il tempo di esecuzione è (n)
Quicksort (A, p, r)
if p < r then
q = Partition (A,p,r)
Quicksort(A, p, q)
Quicksort(A, q+1, r)
Correttezza: la concatenazione di due array ordinati in cui l’array di
sinistra contiene elementi minori o uguali degli elementi dell’array di
destra è un array ordinato
Analisi: T(n) = (n) + T(k) + T(n-k)
Se k sono gli elementi da p a q (e n-k i rimanenti da q+1 a r)
con 1 ≤ k ≤ n-1. Ricorda: Partition restituisce q p.
Analisi Quicksort (caso peggiore)
Un primo caso: ad ogni passo il pivot scelto è il minimo o il
massimo degli elementi nell’array (la partizione è 1 | n-1 ):
T(n) = T(n-1) + T(1) + (n)
essendo T(1)= (1)
T(n) = T(n-1) + (n)
La cui soluzione è T(n) = (n2)
Si può dimostrare che questo è il caso peggiore; quindi per il Quicksort:
T(n) = O(n2)
Un esempio del caso peggiore del Quicksort
Un array ordinato
x = 1
1
2
3
4
5 6
1 2 3 4 5 6
2 3 4 5 6
3 4 5 6
4 5 6
5 6
x = 2
x = 3
x = 4
x = 5
Analisi Quicksort (caso migliore)
Un altro caso: ad ogni passo il pivot scelto è la “mediana” degli elementi nell’array
(la partizione è n/2 | n/2 ):
T(n) = 2 T(n/2) + (n)
La cui soluzione è T(n) = (n log n)
(è la stessa relazione di ricorrenza del Mergesort)
Si può dimostrare che questo è il caso migliore; quindi: T(n) = (n log n)
Riassumendo, per il Quicksort: T(n) = O(n2) e T(n) = (n log n)
Il caso migliore è diverso dal caso peggiore quindi
T(n) non è di nessuna funzione
Algoritmo randomizzato: • Introduce una chiamata a random(a,b) (che restituisce un numero a caso fra a e b (a<b))
• Forza l’algoritmo a comportarsi come nel caso medio
• Non esiste una distribuzione d’input «peggiore» a priori
Nota: sul libro di testo trovate solo una versione randomizzata. Per il resto potete fare riferimento al libro di Cormen, Leiserson, Rivest, (Stein) Introduzione agli algoritmi, o ad altri testi consigliati nel programma.
Il Quicksort non ha un «buon» caso peggiore, ma ha un buon caso medio
(si può dimostrare che anche nel caso medio si comporta come nel caso migliore),
per cui si può considerare una sua versione «randomizzata»
Is Quicksort … quick?
Random-Quicksort (A, p, r)
if p < r then
q Random-Partition (A,p,r)
Random-Quicksort(A, p, q)
Random-Quicksort(A, q+1, r)
Random-Partition (A, p, r)
i random(p,r)
scambia A[i] <-> A[p]
return Partition(A, p, r)
QuickSort randomizzato
Da ricordare sulla complessità dell’ordinamento
Esistono algoritmi di ordinamento con tempo nel caso peggiore (n2) e (nlogn)
Esistono anche algoritmi di ordinamento con tempo nel caso peggiore (n), ma …
non sono basati sui confronti e funzionano solo sotto certe ipotesi.
Inoltre si può dimostrare che tutti gli algoritmi di ordinamento basati sui confronti
richiedono Ω(n log n) confronti nel caso peggiore!
Si dice che Ω(n log n) è una delimitazione inferiore (lower bound) al
problema dell’ordinamento, cioè al numero di confronti richiesti per ordinare n
oggetti.
Delimitazione inferiore (lower bound) =
quantità di risorsa necessaria per risolvere un determinato problema
Indica la difficoltà intrinseca del problema.
25
Integer Arithmetic
Add. Given two n-digit integers a and b, compute a + b.
O(n) bit operations.
Multiply. Given two n-digit integers a and b, compute a × b.
Brute force solution: (n2) bit operations.
1
1
0
0
1
1
1
0
0
1
1
1
1
0
0
1
1
1
1
0
1
0
1
0 0 0 0 0 0 0
1 0 1 0 1 0 1
1 0 1 0 1 0 1
1 0 1 0 1 0 1
1 0 1 0 1 0 1
1 0 1 0 1 0 1
0 0 0 0 0 0 0
1 0 0 0 0 0 0 0 0 0 0 1 0 1 1
1
0
1
1
1
1
1
0
0
*
1
0 1 1 1
1 1 0 1 +
0 1 0 1
1 1 1
0 1 0 1
0 1 1 1
1 0 0 0
1 0 1 1 1
Add
Multiply
Divide –et – Impera per la moltiplicazione Esprimere il prodotto di due interi a n cifre tramite prodotti di due interi con un numero inferiore di cifre.
Esempio: (base 10) 123.456 =123 · 1000 + 456 = 123 · 103 + 456
(base 2) 1101 = 11 · 22 + 01
1101 = 1 · 23 +1 · 22 + 0· 21 + 1· 20 =
= (1 · 2 +1 )· 22 + (0· 21 + 1· 20 )
Dato un intero x a n bit x = x1 · 2 n/2 + x2 dove x1 e x2 hanno n/2 bit
27
To multiply two n-digit integers:
Multiply four pairs of ½n-digit integers.
Add two pairs of ½n-digit integers, and shift to obtain result.
Divide-and-Conquer Multiplication: Warmup
)()T( )( 2/4 )T( 2
shift add,calls recursive
nnnnTn
001001
2/
1101
2/
01
2/
01
2/
01
2/
2 2 22
2
2
yxyxyxyxyyxxxy
yyy
xxx
nnnn
n
n
assumes n is a power of 2
Caso q = 4 >2, T(n)=Θ (n log 2 4)
Non migliore della forza bruta
28
To multiply two n-digit integers:
Add two pairs of ½n digit integers.
Multiply three different pairs of ½n-digit integers (A, B, C).
Add, subtract, and shift ½n-digit integers to obtain result.
Theorem. [Karatsuba-Ofman, 1962]
Can multiply two n-digit integers in O(n1.585) bit operations.
Karatsuba Multiplication
x 2n / 2 x1 x0
y 2n / 2 y1 y0
xy 2n x1y1 2n / 2 x1y0 x0 y1 x0 y0
2n x1y1 2n / 2 (x1 x0 ) (y1 y0 ) x1y1 x0 y0 x0 y0
A B C A C
Karatsuba Algorithm
otherwise )2/(3
2 if2)T(
nnT
nn
T(n) T n /2 T n /2 T 1 n /2 recursive calls
(n)
add, subtract, shift
T(n) O(nlog 2 3
) O(n1.585 )
Per semplificare risolveremo: Caso q = 3 >2,
T(n)=Θ (n log 2 3)
Applicazioni del Master Theorem
Confrontare f(n) con nlogba: qual è «più grande»?
Il più grande (asintoticamente e polinomialmente) vince! Esempio 1: T(n)= 2 T(n/2)+ log n: a = b = 2, f(n)= log n vs nlogba = nlog22 = n1
f(n)=O(n 1-ε ) per ε=1/2, quindi T(n)= Θ(n)
Esempio 2: T(n)= 2 T(n/2)+ n: a = b = 2, f(n) = n vs nlogba= nlog22= n1
f(n)= Θ(n ), quindi T(n)= Θ(n log n)
Esempio 3: T(n)= 2 T(n/2)+ n3: a = b = 2, f(n) = n3 vs nlogba= nlog22= n1
f(n)= Ω(n 1+ε ) e inoltre 2(n/2) 3≤ cn 3 per c= ¼<1
quindi T(n)= Θ(n3)
<
Caso di non applicabilità
T(n)= 2T(n/2)+ n log n
a = b = 2,
f(n) = n log n vs nlogba = nlog22 = n1
f(n) = n log n = Ω(n 1), ma non esiste nessun ε per cui f(n)=Ω(n 1+ε )
Il Master Theorem non si applica a questa relazione di ricorrenza;
bisogna applicare gli altri metodi
Analisi algoritmi ricorsivi
Si usano le stesse regole, tranne che il tempo per le chiamate ricorsive, non conoscendolo esplicitamente, lo lasceremo indicato T(…).
Otterremo così una relazione di ricorrenza per T(n), da risolvere in risolvere in seguito, con i metodi studiati.
Non ci interessa cosa calcoli ma quanto tempo impiega
Supponiamo che il tempo per eseguire qualcosa sia c