44
Quicksort Moltiplicazione di interi Master Theorem Valutazione del tempo di esecuzione di algoritmi iterativi e ricorsivi

Quicksort Moltiplicazione di interi Master Theorem ... · Introduzione agli algoritmi, o ad altri testi consigliati. Quicksort . Quicksort Dato un array di n elementi ... Per il resto

Embed Size (px)

Citation preview

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

Quicksort vs Mergesort (entrambi divide et impera)

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.

5.5 Integer Multiplication

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)

Master Theorem

Master Theorem Teorema fondamentale o Teorema dell’esperto

<

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

Valutazione del tempo di esecuzione di algoritmi iterativi e ricorsivi

1 ≤ k ≤ n

Non ci interessa cosa calcoli ma quanto tempo impiega

T(n) = Θ (k)

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