Sei sulla pagina 1di 5

Algoritmi e Programmazione

Il paradigma divide et impera

Merge Sort (von Neumann, 1945)

Gli algoritmi ricorsivi di ordinamento

Paolo Camurati Dip. Automatica e Informatica Politecnico di Torino

Divisione: due sottovettori SX e DX rispetto al centro del vettore.


l r

l
A.A. 2013/14 07 Gli ordinamenti ricorsivi

q q+1

r
2

Esempio
Ricorsione merge sort su sottovettore DX merge sort su sottovettore SX condizione di terminazione: con 1 (l=r) o 0 (l>r) elementi ordinato Ricombinazione: fondi i due sottovettori ordinati in un vettore ordinato.

A.A. 2013/14 07 Gli ordinamenti ricorsivi 3 A.A. 2013/14

Divisione ricorsiva:
12 6 4 5 9 2 3 1 12 6 4 5 12 6 12 6 4 4 5 5 9 2 3 1 9 2 9 2 3 3 1 1

07 Gli ordinamenti ricorsivi

Ricombinazione
void MergeSort(Item A[], int l, int r) { divisione int q = (l + r)/2; if (r <= l) terminazione return; chiamata ricorsiva MergeSort(A, l, q); MergeSort(A, q+1, r); chiamata ricorsiva Merge(A, l, q, r); }

1 2 3 4 5 6 9 12 4 5 6 12 6 12 12 6 4 4 5 5 1 2 3 9 2 9 9 2 3 1 3 1

ricombinazione
A.A. 2013/14 07 Gli ordinamenti ricorsivi 5 A.A. 2013/14 07 Gli ordinamenti ricorsivi 6

Algoritmi e Programmazione

Il paradigma divide et impera

Caratteristiche
void Merge(Item A[], int l, int q, int r) { int i, j, k; Item B[MAX]; i = l; j = q+1; for (k = l; k <= r; k++) if (i > q) B[k] = A[j++]; else if (j > r) B[k] = A[i++]; else if ( less(A[i], A[j]) || eq(A[i], A[j]) B[k] = A[i++]; else B[k] = A[j++]; for ( k = l; k <= r; k++ ) A[k] = B[k]; return; }
A.A. 2013/14 07 Gli ordinamenti ricorsivi

Non in loco (usa un vettore ausiliario) Stabile: in quanto la funzione merge prende dal sottovettore SX in caso di chiavi uguali:
11 12 13 14 4 5 7 9

11 12 13 4

14 5 7 9

A.A. 2013/14

07 Gli ordinamenti ricorsivi

Analisi asintotica di caso peggiore


Ipotesi: n = 2k. Dividi: calcola la met di un vettore D(n)=(1) Risolvi: risolve 2 sottoproblemi di dimensione n/2 ciascuno 2T(n/2) Terminazione: semplice test (1) Combina: basata su Merge C(n) = (n) C(n) + D(n) = (n) Equazione alle ricorrenze: T(n) = 2T(n/2) + n n>1 T(1) = 1 n=1
A.A. 2013/14 07 Gli ordinamenti ricorsivi 9

soluzione per sviluppo (unfolding) T(n/2) = 2T(n/4) +n/2 T(n/4) = 2T(n/8) +n/4 etc.

Terminazione: a ogni passo i dati si dimezzano, dopo i passi sono n/2i . Si termina per n/2i = 1, i = log2n T(n) = n + 2*(n/2) + 22 *(n/4) + 23 *T(n/8) = 0 i log2n 2i / 2i * n = n * 0 i log2n 1 = n*(1 + log2n) n log2n + n T(n) = O(n log n)
A.A. 2013/14 07 Gli ordinamenti ricorsivi 10

Bottom-up Merge Sort


Intuitivamente: Versione non ricorsiva Ipotesi per semplificare: n = 2k Partendo da sottovettori di lunghezza 1 (quindi ordinati), si applica Merge per ottenere a ogni passo vettori ordinati di lunghezza doppia Terminazione: il vettore ha dimensione pari a quello di partenza.

Livelli di ricorsione: log2 n Operazioni per livello: n Operazioni totali: n log2 n


A.A. 2013/14 07 Gli ordinamenti ricorsivi 11 A.A. 2013/14 07 Gli ordinamenti ricorsivi 12

log2 n

Algoritmi e Programmazione

Il paradigma divide et impera

12

raddoppia la dimensione del vettore ordinato void BottomUpMergeSort(Item A[], int l, int r) { int i, m; for (m = 1; m <= r l; m = m + m) for (i = l; i <= r m; i += m + m) Merge(A, i, i+m-1, r); } fondile

6 12

4 5

2 9

1 3

4 5 6 12

1 2 3 9

1 2 3 4 5 6 9 12
considera le coppie di sottovettori ordinati di dimensione m
A.A. 2013/14 07 Gli ordinamenti ricorsivi 13 A.A. 2013/14 07 Gli ordinamenti ricorsivi 14

Quicksort (Hoare, 1961)

Divisione: partiziona il vettore A[p..r] in due sottovettori SX e DX: dato un elemento pivot x = A[q] SX A[p..q-1] contiene tutti elementi x DX A[q+1..r] contiene tutti elementi x A[q] si trova al posto giusto la divisione non necessariamente a met, a differenza del mergesort.
07 Gli ordinamenti ricorsivi 15 A.A. 2013/14

Ricorsione quicksort su sottovettore SX A[p..q-1] quicksort su sottovettore DX A[q+1..r] condizione di terminazione: se il vettore ha 1 elemento ordinato Ricombinazione: nulla.

A.A. 2013/14

07 Gli ordinamenti ricorsivi

16

Partition
Pivot x = A[r] individua A[i] e A[j] elementi fuori posto ciclo discendente j fino a trovare un elemento minore del pivot x ciclo ascendente su i fino a trovare un elemento maggiore del pivot x scambia A[i] e A[j] ripeti fintanto che i < j alla fine scambia A[i] e il pivot x ritorna i T(n) = (n).

A.A. 2013/14 07 Gli ordinamenti ricorsivi 17

Esempio di partition
A i A 25 17 2 6 4 1 0 13 i A j A p r 25 17 2 6 14 1 0 13 j A

x 13

0 1 2 6 4 17 25 13 j i scambio di i e j

return q

0 1 2 6 4 13 25 17 j i

0 17 2 6 4 1 25 13 i j
07 Gli ordinamenti ricorsivi

A.A. 2013/14

18

Algoritmi e Programmazione

Il paradigma divide et impera

Esempio di quicksort
A x 4 x 2 x 1 0 25 17 2 6 4 1 0 13 13 6 17 25 17 25 x 13 x 17
void quicksort (Item A[], int l, int r ){ int q; discesa ricorsiva/terminazione if (r <= l) return; divisione q = partition(A, l, r); quicksort(A, l, q-1); chiamata ricorsiva quicksort(A, q+1, r); return; chiamata ricorsiva } void Swap(Item v[], int n1, int n2) { Item temp; temp = v[n1]; v[n1] = v[n2]; v[n2] = temp; return; }
19 A.A. 2013/14 07 Gli ordinamenti ricorsivi 20

0 1 2 6 4 0 1 2 0 1 1 2 A 4

0 1 2 4 6 13 17 25

A.A. 2013/14

07 Gli ordinamenti ricorsivi

Caratteristiche
int partition (Item A[], int l, int r ){ int i = l-1, j = r; Item x = A[r]; for ( ; ; ) { while(less(A[++i], x)); while(greater(A[--j], x)); if (j == l) break; if (i >= j) break; Swap(A, i, j); } Swap(A, i, r); return i; }
A.A. 2013/14 07 Gli ordinamenti ricorsivi 21

In loco Non stabile: la funzione partition pu provocare uno scambio tra elementi lontani, facendo s che unoccorrenza di una chiave duplicata si sposti a SX di unoccorrenza precedente della stessa chiave scavalcandola.

A.A. 2013/14

07 Gli ordinamenti ricorsivi

22

Analisi asintotica di caso peggiore


Efficienza legata al bilanciamento delle partizioni A ogni passo partition ritorna: caso peggiore un vettore da n-1 elementi e laltro da 1 caso migliore due vettori da n/2 elementi caso medio due vettori di dimensioni diverse. Bilanciamento legato alla scelta del pivot.
A.A. 2013/14 07 Gli ordinamenti ricorsivi 23 A.A. 2013/14

Caso peggiore
Caso peggiore: pivot = minimo o massimo (vettore gi ordinato) Equazione alle ricorrenze: T(n) = T(n-1) + n n>=2 T(1) = 1 n=1 Risoluzione per sviluppo: T(n) = n + (n-1) + (n-2) + . 3 + 2 + 1 = n/2 * (n+1) T(n) = O(n2)

07 Gli ordinamenti ricorsivi 24

Algoritmi e Programmazione

Il paradigma divide et impera

Caso migliore

Caso medio
Purch non si ricada nel caso peggiore, anche se il partizionamento molto sbilanciato, caso medio = caso migliore Esempio: ad ogni passo si generano 2 partizioni, la prima con 9/10 n e la seconda con n/10 elementi.

Equazione alle ricorrenze: T(n) = 2T(n/2) + n T(1) = 1 T(n) = O(n lg n)

n>=2 n=1

A.A. 2013/14

07 Gli ordinamenti ricorsivi

25

A.A. 2013/14

07 Gli ordinamenti ricorsivi

26

Scelta del pivot


n n/10 log10 n n/100 9n/100 9n/10 9n/100 81n/100 n n n log10/9 n 1

T(n) = O(n lg n)
A.A. 2013/14 07 Gli ordinamenti ricorsivi

Elemento a caso: genera un numero casuale i con l i r, poi scambia A[0] e A[i], usando come pivot A[0] Elemento di mezzo: x A[(l+r)/2] Scegliere il valore medio tra min e max Scegliere la mediana tra 3 elementi presi a caso nel vettore

27 A.A. 2013/14 07 Gli ordinamenti ricorsivi 28

Quadro riassuntivo
Algoritmo Bubble sort Selection sort Insertion sort Shellsort Mergesort Quicksort Counting sort
A.A. 2013/14

Riferimenti

In loco Stabile Caso peggiore s s O(n2) s s O(n2) s s O(n2) s no dipende no s O(nlog n) s no O(n2) no s O(n)
07 Gli ordinamenti ricorsivi 29

Mergesort e Bottom-up mergesort


Sedgewick 8.3 e 8.5 Cormen 1.3 Quicksort Sedgewick 7.1 e 7.2 Cormen 8.1, 8.2

A.A. 2013/14

07 Gli ordinamenti ricorsivi

30