Laboratorio di didattica dell’informatica generale Prof. Carlo Fusco Algoritmi di ordinamento ricorsivi Calzetta Emilia Cervone Vincenzo Coppola Maria Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Programmazione didattica Titolo: Algoritmi di ordinamento ricorsivi Classe: 3^ I.T.I.S. Contenuti: Significato dell’ordinamento; Ripetizione dei concetti di Iterazione ricorsione, Algoritmi ricorsivi (quick-sort, merge-sort); Analisi e comparazione degli algoritmi; Implementazione degli algoritmi con le macro di Excell Prerequisiti: Conoscenze sull’organizzazione dei dati mediante la struttura vettoriale Conoscenze della teoria della ricorsione e dell’iterazione Conoscenze della teoria e implementazione degli algoritmi Conoscenze delle macro di Excel Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Programmazione didattica Obiettivi: Saper gestire l’organizzazione e ordinamento dei dati in un vettore Capire l’importanza dell’ordinamento dei dati Utilizzare le strutture di iterazione e ricorsione Analizzare le applicazioni relative agli argomenti teorici affrontati Modalità di lavoro: lezioni frontali utilizzo del laboratorio Riferimenti: A. Lorenzi, D. Rossi- Basi teoriche dell’informatica: progettazione degli algoritmi Atlas Cormen, Leiserson, Rivest- Introduzione agli algoritmi -McGrawHill A. Lorenzi, D. Rossi- Informatica teoria e programmazione in Visual Basic per le Scuole superiori -Atlas Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Ordinamento di un vettore Il problema dell’ordinamento crescente di un vettore (array) di interi è caratterizzato come segue: dato un vettore A di elementi interi, trasformarlo in modo tale che, per ogni indice i, l’elemento A[i] sia minore o uguale di tutti gli altri elementi di dati di indice j, con i<j Esempio: A = [10,2,13,4] Vettore iniziale A = [2,4,10,13] Vettore ordinato A[i] ≤ A[j] con i, j =1, …,4 , i<j Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Importanza dell’ordinamento L’accesso a collezioni di dati ordinate in modo opportuno è più semplice che non l’accesso a collezioni non ordinate. •A che servirebbe un elenco telefonico se gli utenti fossero elencati in ordine sparso? •A che servirebbe un elenco telefonico se gli utenti fossero elencati per numero telefonico crescente? Anche nei calcolatori, è spesso utile gestire collezioni di dati ordinate secondo un qualche criterio di ordinamento, questo ad esempio permette di usare algoritmi di ricerca più efficienti (ricerca binaria) Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Problema: ordinare in ordine crescente una sequenza di studenti considerando le chiavi di ordinamento: età, nome, media scolastica Luca 18 anni Media=5 Antonio 14 anni Media=9 Gianni 17 anni Media=8 Marco 16 anni Media=7 Carlo 15 anni Media=6 Ordinamento crescente per età Antonio 14 anni Media=9 Carlo 15 anni Media=6 Università degli Studi di Napoli Parthenope Marco 16 anni Media=7 Gianni 17 anni Media=8 Luca 18 anni Media=5 SICSI V CICLO classe A042 Ordinamento crescente per nome Antonio 14 anni Media=9 Carlo 15 anni Media=6 Gianni 17 anni Media=8 Luca 18 anni Media=5 Marco 16 anni Media=7 Ordinamento crescente per media scolastica Luca 18 anni Media=5 Carlo 15 anni Media=6 Università degli Studi di Napoli Parthenope Marco 16 anni Media=7 Gianni 17 anni Media=8 Antonio 14 anni Media=9 SICSI V CICLO classe A042 Iterazione e ricorsione Gli algoritmi di ordinamento possono essere iterativi e ricorsivi Iterazione: ripetere piu’ volte una sequenza di operazioni Esempio: somma i primi n interi: ( ( ( (1)+ 2) +3)+…+ n) for (i=1, i<=n, i++) somma=somma +i La caratteristica fondamentale di un algoritmo ITERATIVO è che a ogni passo è disponibile un risultato parziale: dopo k passi, si ha a disposizione il risultato parziale relativo al caso k Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Iterazione e ricorsione Gli algoritmi ricorsivi si basano sulla possibilità di definire una funzione in termini di se stessa. Una funzione è definita ricorsivamente quando nella sua definizione compare un riferimento a se stessa. Esempio: somma i primi n iteri Sn= n + Sn-1 n + somma dei primi (n-1) numeri iteri Risolvere un problema con un approccio ricorsivo comporta: • identificare un “caso base” la cui soluzione sia nota • riuscire a esprimere la soluzione al caso generico n in termini dello stesso problema in uno o più casi più semplici (n-1, n-2, etc). Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Esempio di funzione ricorsiva: Sn= n + Sn-1 somma dei primi n iteri n + soluzione del problema della somma dei primi (n-1) iteri “somma dei primi (n-1) interi” è una istanza più semplice del problema “somma dei primi n interi” e tale istanza può essere scomposta, a sua volta, in un’istanza ancora più semplice Sn= n+(n-1)+Sn-2 Procedendo in queste scomposizioni si giunge fino all’istanza banale del problema S1= 1 Sn= n+(n-1)+(n-2)+(n-3)+…+1 Osserviamo che nella ricorsione, a differenza dell’iterazione, non si dispone di un risultato parziale finché non si è giunti fino all’istanza elementare Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Algoritmi di ordinamento ricorsivi Il motto latino ‘Divide et Impera’ è stato acquisito dall’informatica come tecnica per risolvere problemi complessi, in pratica si genera una sequenza di istanze via via più semplici del problema, fino all'istanza che non è più suddivisibile e che ha soluzione banale Il Quick-sort e il Merge-sort sono due algoritmi di ordinamento ricorsivi che si basano sulla tecnica ‘Divide et Impera’ “DIVIDE ET IMPERA” Dividi e domina dicevano i latini: sia con il significato che una volta conquistato un nuovo territorio è meglio tenere diviso il popolo, se è ostile, per evitare rivolte e sovversioni; sia con il significato di partizionare il territorio per amministrarlo meglio. Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-sort (ordinamento veloce) Il Quick-sort è uno degli algoritmi di ordinamento più diffusi, esso lavora partizionando l’array da ordinare, e quindi ordinandone ricorsivamente ogni partizione. Uno degli elementi dell’array viene scelto come valore di pivot (di perno), i valori inferiori o uguali al pivot vengono messi alla sua sinistra, mentre i valori superiori vengono messi alla sua destra. Quindi il quick-sort è un algoritmo ricorsivo basato sul Divide et Impera: Divide: si “partiziona” il vettore A[1…n] spostando i suoi elementi in due sottovettori A[1…q-1] e A[q+1…n], separati da un elemento pivot A[q]. Ogni elemento di A[1…q-1] è A[q]; Ogni elemento di A[q+1…n] è > A[q] il pivot A[q] viene spostato nella posizione corretta del vettore ordinato Impera: si ordinano ricorsivamente i due sottovettori A[1…q] e A[q+1…n] con il Quick-sort, fino a generare vettori di 1 solo elemento (che sono banalmente ordinati!) Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Pseudocodice del Quick-Sort Indice mediano Quick-Sort(A,s,d) IF s < d THEN q = Partiziona(A,s,d) Quick-Sort(A,s,q-1) Quick-Sort(A,q+1,d) q è l’indice che divide il vettore A in due in modo che gli elementi con indice q siano minori o uguali a quelli con indice > q Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Pseudocodice del Quick-Sort Quick-Sort(A,s,d) Ordinamento dei due sottoarray IF s < d THEN q = Partiziona(A,s,d) Quick-Sort(A,s,q-1) Quick-Sort(A,q + 1,d) Poiché il primo sottovettore ha elementi tutti minori o uguali a quelli del secondo sottovettore, basta ordinare separatamente i due sottovettori per risolvere l’intero problema Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Pseudocodice del Quick-Sort passo Divide Quick-Sort(A,s,d) IF s < d THEN q = Partiziona(A,s,d) Quick-Sort(A,s,q-1) Quick-Sort(A,q++1,d) 1,d) Quick-Sort(A,q passo Impera Divide: Partiziona è la chiave dell’algoritmo! Impera: si ordinano ricorsivamente i due sottovettori A[s…q] e A[q+1…d] con Quick-Sort Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,s,d) Partiziona(A,s,d) x = A[d] i = s - 1 j = s WHILE j < d DO Scegliamo come pivot (perno) l’ultimo elemento dell’array e poi spostiamo gli elementi maggiori del pivot verso destra e gli elementi minori verso sinistra. IF A[j] x THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 L’indice mediano q dipende dall’elemento è il numero di elementi minori o uguali al pivot Università degli Studi di Napoli Parthenope pivot: SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) Scegliamo come elemento di pivot l’ultimo elemento dell’array da ordinare pivot Partiziona(A,s,d) 1 x = A[d] 2 3 4 5 6 7 8 9 10 11 x 12 20 14 28 34 15 45 12 30 21 25 16 22 i = s - 1 j = s i j WHILE j < d DO IF A[j] x THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) x Partiziona(A,s,d) x = A[d] 1 2 3 4 5 6 7 8 9 10 11 12 i = s - 1 20 14 28 34 15 45 12 30 21 25 16 22 j = s i j WHILE j < d DO IF A[j] x THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) x Partiziona(A,s,d) x = A[d] 1 2 3 4 5 6 7 8 9 10 11 12 20 14 28 34 15 45 12 30 21 25 16 22 i = s - 1 j = s i j WHILE j < d DO IF A[j] x THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) x Partiziona(A,s,d) x = A[d] 1 2 3 4 5 6 7 8 9 10 11 12 20 14 28 34 15 45 12 30 21 25 16 22 i = s - 1 j = s i j WHILE j < d DO IF A[j] x THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) x Partiziona(A,s,d) x = A[d] 1 2 3 4 5 6 7 8 9 10 11 12 20 14 28 34 15 45 12 30 21 25 16 22 i = s - 1 j = s i j WHILE j < d DO IF A[j] x THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) x Partiziona(A,s,d) x = A[d] 1 2 3 4 5 6 7 8 9 10 11 12 15 34 15 28 45 12 30 21 25 16 22 20 14 28 i = s - 1 j = s i WHILE j < d DO IF A[j] x j j Scambia 15 e 28 THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) x Partiziona(A,s,d) x = A[d] 1 2 3 4 5 6 7 8 9 10 11 12 20 14 15 34 28 45 12 30 21 25 16 22 i = s - 1 j = s i j WHILE j < d DO IF A[j] x THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) x Partiziona(A,s,d) x = A[d] 1 2 3 4 5 6 7 8 9 10 11 12 20 14 15 12 34 28 45 34 12 30 21 25 16 22 i = s - 1 j = s i WHILE j < d DO IF A[j] x j j Scambia 34 e 12 THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) x Partiziona(A,s,d) x = A[d] 1 2 3 4 5 6 7 8 9 10 11 12 20 14 15 12 28 45 34 30 21 25 16 22 i = s - 1 j = s i j WHILE j < d DO IF A[j] x THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) x Partiziona(A,s,d) x = A[d] 1 2 3 4 5 6 7 8 9 10 11 12 21 45 34 30 28 20 14 15 12 28 21 25 16 22 i = s - 1 j = s i WHILE j < d DO IF A[j] x j j Scambia 28 e 21 THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) x Partiziona(A,s,d) x = A[d] 1 2 3 4 5 6 7 8 9 10 11 12 20 14 15 12 21 45 34 30 28 25 16 22 i = s - 1 j = s i j WHILE j < d DO IF A[j] x THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) x Partiziona(A,s,d) x = A[d] 1 2 3 4 5 6 7 8 9 10 11 12 16 34 30 28 25 16 45 22 20 14 15 12 21 45 i = s - 1 j = s i j j WHILE j < d DO IF A[j] x Scambia 45 e 16 THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-Sort: Partiziona(A,1,12) x Partiziona(A,s,d) x = A[d] i = s - 1 1 2 3 4 5 6 7 8 9 10 11 12 22 30 28 25 45 34 20 14 15 12 21 16 34 22 j = s i WHILE j < d DO j Sposta il pivot IF A[j] x THEN i=i+1 “scambia A[i] con A[j]” j = j+1 “scambia A[i+1] con A[d]” RETURN i+1 Università degli Studi di Napoli Parthenope l’elemento di pivot (22) è stato spostato nella posizione che occuperà nel vettore ordinato SICSI V CICLO classe A042 Quick-sort (ordinamento dei sottoarray) 22 30 28 25 45 34 20 14 15 12 21 16 34 Applica il QuickSort ai sottoarray 14 12 16 20 16 21 20 15 14 15 12 21 45 30 28 25 34 45 34 22 Pivot=16 14 15 12 14 12 15 16 20 Pivot=34 21 22 25 30 28 28 30 25 28 30 25 34 45 12 14 15 15 20 21 22 25 28 30 34 45 Vettore ordinato! Il quick-sort è un algoritmo che non crea nuovi vettori ma sposta gli elementi nel vettore di input servendosi di locazioni di memoria ausiliarie in numero fisso Università degli Studi di Napoli Parthenope QuickSort(A,p,n) if p < n then q := Partition(A; p; n) QuickSort(A; p; q - 1) QuickSort(A; q + 1; r) endif SICSI V CICLO classe A042 QuickSort: analisi di complessità Il tempo di esecuzione di QuickSort dipende dall’input e dalla scelta dell’elemento di pivot, in pratica dipende dal bilanciamento fra i sottovettori costruiti dal Divide •Il caso migliore si verifica quando i sottovettori sono perfettamente bilanciati, entrambi di dimensione n/2 Siccome l’array viene diviso in due ad ogni passo e devono comunque essere esaminati tutti gli n elementi, il tempo di esecuzione tende a (n logn), se n è la dimensione dell’array di input •Il caso peggiore si verifica quando un sottovettore è sempre di dimensione 1 (l’altro è quindi di dimensione n - 1). In questo caso il tempo di esecuzione tende a (n2), cioè cresce al più come il quadrato della dimensione dell’array di input Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-sort (Caso peggiore) Il caso peggiore si ha se il vettore in input è già ordinato e si sceglie come pivot il minimo o il massimo degli elementi. Supponiamo che l’array è ordinato. Se si decide di scegliere come pivot il primo elemento della sequenza, e cioè l’elemento minore, si avrebbe che l’array ha un elemento nella partizione di sinistra, e gli altri elementi nell’altra, perché sarebbero tutti maggiori del pivot. 12 14 15 18 21 34 45 Ogni chiamata ricorsiva di quicksort ridurrebbe solo di un’unità la dimensione dell’array da ordinare. Sarebbero quindi necessarie n chiamate ricorsive per effettuare l’ordinamento, portando a un tempo di esecuzione dell’ordine di (n2). Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Quick-sort (scelta del pivot) Una soluzione a questo problema si può ottenere scegliendo a caso il pivot tra gli elementi della sequenza. La probabilità di selezionare proprio l’elemento più piccolo dell’array e’ ad ogni passo uguale ad 1/n, cioè e’ inversamente proporzionale alla lunghezza dell’array. Quindi scegliendo a caso il pivot, anche se la sequenza è già ordinata, e se gli elementi sono sufficientemente numerosi, risulta altamente improbabile che il pivot scelto sia l’elemento più piccolo (o il più grande) e in questo caso il problema si riconduce al caso medio, cioè al caso in cui i sottovettori sono sempre di dimensioni diverse Nonostante le cattive prestazioni nel caso peggiore, QuickSort è il miglior algoritmo di ordinamento in media. (tempo di esecuzione del caso migliore = tempo di esecuzione del caso medio) Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Merge-sort (ordinamento per fusione) Anche il Merge-sort è formulato ricorsivamente (divide et impera) ma a differenza del Quick-sort usa una procedura di fusione per ottenere l’array finale ordinato. In pratica l’algoritmo Merge-sort divide ripetutamente il vettore di input a metà, finché si generano segmenti contenenti uno o due componenti, poi ciascun segmento viene ordinato e si effettua la fusione fra i segmenti in sequenza inversa rispetto alla fase di divisione: Se l’array ha due elementi, essi vengono confrontati e scambiati se non sono ordinati Se l’array ha più di due elementi lo si divide a metà (‘divide’) e si ordinano i due array ottenuti usando lo stesso metodo ricorsivamente (‘impera’). Infine gli array vengono fusi per formare l’array ordinato (fusione) Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 MergeSort(A, p, r) Esempio: Si A il vettore da ordinare if p < r then q := (p + r) / 2 Dividi a metà! A 3 6 11 1 12 5 8 7 MergeSort(A; p; q) MergeSort(A; q + 1; r) Merge(A; p; q; r) endif Dividi a metà 3 6 11 1 12 35 68 117 1 12 5 ricorsivamente! 8 3 6 11 13 12 113 816 12 711351 6812 11751 812 75 6 5 7 8 7 Ogni array viene ordinato con un semplice confronto tra i suoi due elementi! 11 3 5715 11 8 71 8 57 8 3 6 11 37 11 3 16 12 11 12 812 33 5166 8 11 1516 12 6 812 57 12 Università degli Studi di Napoli Parthenope 7 SICSI V CICLO classe A042 Fusione di due array ordinati Dati due array B e C ciascuno con n1 e n2 componenti ordinate in ordine crescente, si vuole ottenere un unico array D ordinato costituito dai n1+n2 elementi di B e C. 1. Sia i l’indice per scandire B, j l’indice per scandire C e k l’indice che usiamo per costruire l’array D 2. Inizializziamo k=1, i=1, j=1 3. Se B[i]<C[j] allora D[k]=B[i], incrementa i e k; altrimenti D[k]=C[j], incrementa j e k; 4. Ripetere il passo 3 finchè uno dei due array (o entrambi) non è esaurito. 5. Inserire gli elementi dell’array non ancora esaurito nelle posizioni restanti di C Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Esempio fusione (Merge): Consideriamo i vettori ottenuti nella precedente scomposizione 11 3 5715 11 8 71 8 57 8 3 6 11 37 11 3 16 12 11 12 812 33 5166 8 11 1516 12 6 812 57 12 1 5 3 6 11 7 7 8 12 8<12 Facciamo il merge dei due vettori ottenuti! 5<7 7<12 1<3 3<11 6<11 1 3 5 6 7 8 11 12 Vettore ordinato! 5<66<7 8<11 11<12 1<5 3<5 7<11 Università degli Studi di Napoli Parthenope Merge(B,C,D,n,m) i=1, i=1, i=1,j=1, j=1, j=1,k=1 k=1 k=1 for i=1 to n do B[i]<C[j] then then IfIf B[i]<C[j] D[k]=B[i], i=i+1, i=i+1, k=k+1 k=k+1 D[k]=B[i], else else D[k]=C[j], j=j+1, j=j+1, k=k+1 k=k+1 D[k]=C[j], endif endif endfor While j<=m do D[k]=C[j], j=j+1,k=k+1 endwhile SICSI V CICLO classe A042 Complessità Merge-sort L’operazione dominante del merge-sort è la fusione di sottosequenze ordinate, il costo di questo algoritmo di ordinamento dipende quindi da quante volte viene eseguita la fusione e da quanto costa ciascuna operazione di fusione Analizziamo il tempo di esecuzione: Sia M(n) il numero di confronti, nel caso peggiore, che MergeSort opera con un input di dimensione n. Sia T(n) una funzione per il tempo di esecuzione dell’algoritmo, tale che M(n) T(n) T(n) = 0, se n=1 questo e' il caso base ( se c’è un solo elemento nell’array non si spende tempo) Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Nel caso n2, il numero dei confronti fatti per ordinare n elementi e' al più uguale alla somma del numero di confronti fatti nel caso peggiore per ciascuno dei seguenti passi dell’algoritmo: 1. Ordina la parte sinistra dell'array 2. Ordina la parte destra dell'array 3. Unisci (merge) le due parti in un array ordinato Quindi: T(n) = T(n/2) + T(n/2) + n, se n2 Osserviamo che: Il primo termine (T(n/2)), fissa un limite superiore al numero di confronti necessari ad ordinare la parte sinistra dell'array, che consiste della metà degli elementi dell'intero array. Il secondo termine (T(n/2)), fissa un limite superiore al numero di confronti necessari ad ordinare la parte destra dell'array. L'ultimo termine (n), fissa un limite superiore ai confronti necessari a comporre i due array ordinati di n componenti Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Esempio: sia n=8, come calcoliamo T(8)? Dobbiamo scomporre la relazione fintanto che non arriviamo al passo base: T(8) = 2T(4) + 8 T(4) = 2T(2) + 4 T(2) = 2T(1) + 2 T(1) = 0 A questo punto possiamo fare le opportune sostituzioni come segue: T(1) = 0 T(2) = 2T(1) + 2 = 0 + 2 T(4) = 2T(2) + 4 = 4 + 4 = 8 T(8) = 2T(4) + 8 = 16 + 8 = 24 In questo caso, il merge-sort richiede al piu' 24 confronti per ordinare 8 elementi, M(8)24 Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Dimostriamo che per n in generale risulta M(n)n.logn Infatti: dall’equazione T(n) = 2T(n/2) + n, n 2 T(1) =0 Per semplificare consideriamo n=2k, (k=log 2n): T(2k ) = 2T(2k-1) + 2k = 4 T(2k -2 )+ 2.2k = 8 T(2k -3 )+ 3.2k =…= 2i T(2k -i ) + i.2k Quando i=log 2n si ha: T(n)= 2 log n T(1) + n.logn = 0 + n.logn Quindi il merge-sort richiede un tempo di esecuzione di al più n log n, se n è la lunghezza dell’array da ordinare. Il merge-sort è, per array di grandi dimensioni, è il più efficiente algoritmo di ordinamento basato sui confronti, perché anche nel caso pessimo ha un tempo di esecuzione di al più nlogn e non esistono algoritmi di ordinamento di array basati sui confronti che hanno un tempo di esecuzione inferiore. Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Merge-sort VS Quick-sort Il quick-sort suddivide il vettore in due sottovettori delimitati dall’elemento ‘pivot’, l’algoritmo vorrebbe suddividere a ogni passo il vettore in due sottovettori uguali ma non sempre ci riesce, al contrario del merge sort che ogni volta spezza il vettore a metà. In pratica il quick-sort riesce al più a emulare il merge-sort, ma senza riuscire a eguagliarlo in tutti i casi. Dipende tutto dalla scelta del pivot! Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Prestazioni degli algoritmi di sorting Le prestazioni degli algoritmi possono essere confrontate con diversi metodi. Uno di questi consiste nella stima del tempo richiesto cioè nel valutare un limite superiore al tempo di esecuzione del algoritmo. Dire che un algoritmo ha un tempo di esecuzione di al più n2 significa che il suo tempo di esecuzione non cresce più del quadrato della dimensione n del suo input n 1 16 256 4.096 65.536 1.048.476 16.775.616 lg n n lg n n2 0 0 1 4 64 256 8 2.048 65.536 12 49.152 16.777.216 16 1.048.565 4.294.967.296 20 20.969.520 1.099.301.922.576 24 402.614.784 281.421.292.179.456 In questa tabella sono indicati i fattori di crescita delle varie funzioni per la stima dei tempi degli algoritmi Se i valori nella tabella rappresentano microsecondi, allora un algoritmo con un tempo di esecuzione di al più (lgn) può impiegare 20 microsecondi per processare 1.048.476 elementi, mentre un algoritmo che richiede un tempo di esecuzione di al più( n2) può impiegare fino a 12 giorni! Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Prestazioni degli algoritmi di sorting (risultati sperimentali) Un altro modo per confrontare le prestazioni degli algoritmi di ordinamento consiste, semplicemente, nell’eseguire molti test per ogni algoritmo al crescere della dimensione n dell’input e nel confrontarne i tempi di esecuzione misurati. Questi sono i risultati forniti da un programma (eseguito su un Pentium 3 di 500 MegaHertz) utilizzato per ordinare con diversi algoritmi un vettore di 30.000 elementi. I tempi sono nella forma minuti secondi. Università degli Studi di Napoli Parthenope SICSI V CICLO classe A042 Implementazione degli algoritmi di sorting Analizziamo delle semplici simulazioni degli algoritmi di sorting che sono state sviluppate con le macro di Microsoft Excel Gli algoritmi di sorting si possono implementare in svariati modi (Java, linguaggio C, Visual Basic, etc.) noi abbiamo scelto il modo più semplice, usando le macro di Excel. Questa scelta è mirata a motivare l’interesse di tutti gli alunni, compresi quelli che potrebbero ritenere ‘difficile’ l’uso di metodi più sofisticati Università degli Studi di Napoli Parthenope Esempi SICSI V CICLO classe A042