28 ottobre Mergesort F. Bombi 28 ottobre 2003
2Lalgoritmo Lalgoritmo di ordinamento mergesort o per fusione è un algoritmo efficiente in quanto ha una complessità temporale O(nlog(n)) e può essere utilizzato per ordinare un vettore di oggetti Comparable oppure una lista o sequenza Lalgoritmo si basa sullesistenza di un algoritmo efficiente in grado di fondere due vettori (o due liste) ordinate in un vettore (o in una lista) ordinata in un tempo O(n+m) essendo n ed m la lunghezza dei due vettori
28 ottobre Per ordinare un vettore Dividere il vettore s d c s1d1s2d2
28 ottobre private void merge (int s1, int d1, int s2, int d2) { int i = s1; int j = s1; while (s1 <= d1 && s2 <= d2) if (v[s1].compareTo(v[s2]) < 0) tmp[i++] = v[s1++]; else tmp[i++] = v[s2++]; while (s1 <= d1) tmp[i++] = v[s1++]; while (s2 <= d2) tmp[i++] = v[s2++]; for (; j <= d2; j++) v[j] = tmp[j]; } Fusione di due array
28 ottobre 20035Analisi Ogni operazione elementare richiede un tempo costante, alla fine la lista l avrà una lunghezza pari a n+m e di conseguenza le operazioni necessarie sono n+m e quindi lalgoritmo ha una complessità O(n+m) Il numero di confronti necessari è al minimo pari a n (oppure a m ) se una delle due liste è composta da elementi minori degli elementi dellaltra lista, è invece O(n+m) se gli elementi delle due liste sono intercalati Lalgoritmo può essere usato per fondere due vettori parzialmente riempiti in un vettore ordinato con efficienza analoga, si utilizzeranno tre cursori per tenere traccia della posizione della testa dei due vettori dorigine e della posizione della coda nel vettore risultato
28 ottobre Per ordinare un vettore Fondere due vettori 214 s1 d1 s2 d2 Vettore temporaneo
28 ottobre 20037Ordinare Sia v larray da ordinare Siano i e s i cursori che definiscono inizio e fine dellarray se larray ha lunghezza > 1 dividere larray in due metà individuate da i1, s1 e i2, s2 ordinare ricorsivamente da i1 a s1 ordinare ricorsivamente da i2 a s2 fondere le due parti dellarray NB: il caso base si ha quando larray ha lunghezza 0 o 1
28 ottobre private Comparable[] v; Private Comparable[] tmp; private int n; public void ordina () { if (n > 1) { tmp = new Comparable[n]; ms(0, n-1); } private void ms (int s, int d) { int c = (s + d)/2; if (s < c) ms(s, c); if (c+1 < d) ms(c+1, d); merge(s, c, c+1, d); } NB: il codice effettua le chiamate ricorsive solo per array di lunghezze maggiore di 1
28 ottobre , 7, 6, 5, 4, 3, 2, 1 8, 7, 6, 54, 3, 2, 1 8, 76, 54, 32, , 8 5, 6 3, 4 1, 2 5, 6, 7, 81, 2, 3, 4 1, 2, 3, 4, 5, 6, 7, 8 Albero delle chiamate ricorsive per un array di 8 elementi
28 ottobre Analisi di mergesort Vogliamo dimostrare che mergesort ha una complessità temporale O(n log(n)) Supponiamo che ogni operazione sugli array richieda un tempo costante Per semplicità supponiamo anche che la lunghezza n dellarray da ordinare sia una potenza di 2 e quindi si possa dire che n = 2 k Analizziamo il tempo in funzione di k
28 ottobre A meno di costanti (inessenziali nella valutazione del comportamento asintotico dellalgoritmo) possiamo dire che: T(k) = 2 T(k-1) + 2 k T(0) = 1 La ricorrenza ha come soluzione T(k) = (k+1)2 k Infatti questo è vero per k = 0, supponendo che sia vero per un valore qualsiasi di k= k avremo che T(k) = (k+1) 2 k
28 ottobre Dobbiamo dimostrare che è vero T(k+1) = (k+1+1)2 k+1 Infatti dalla ricorrenza iniziale abbiamo: T(k+1) = 2 T(k+1-1) + 2 k+1 Dallipotesi fatta per k = k si ha: T(k+1) = 2(k+1)2 k + 2 k+1 E quindi: T(k+1) = (k+1+1)2 k+1 Che era quanto volevamo dimostrare Ora dato che k=log(n) abbiamo che T(n) = n(log(n)+1) = O(n log(n))