Algoritmi di ordinamento Gli ordinamenti interni sono fatti su sequenze in memoria centrale Gli ordinamenti esterni sono fatti su sequenze in memoria di massa Fondamenti di Informatica Per metodi interni è possibile l’accesso casuale ai dati, mentre per i metodi esterni è possibile solo l’accesso sequenziale o a blocchi di grandi dimensioni 18. Algoritmi di ordinamento in C++ Si usano i metodi esterni quando si hanno limitazioni della RAM del calcolatore rispetto alla quantità di dati Corso di Laurea in Ingegneria Informatica e dell’Automazione A.A. 2012-2013 2° Semestre Prof. Giovanni Pascoschi Fondamenti di Informatica A.A. 2012-2013 Algoritmi di ordinamento a cura di Pascoschi Giovanni 2 Algoritmi di ordinamento Gli algoritmi di ordinamento interno si dividono in: Algoritmi semplici - complessità O(n2) prossima lezione Algoritmi evoluti - complessità O(n*log2n) prossima lezione Algoritmi Semplici di Ordinamento. Algoritmi che presentano una complessità proporzionale a n2, dove n è il numero di informazioni da ordinare. Essi sono caratterizzati da poche e semplici istruzioni, dunque presentano un codice molto ristretto. Algoritmi Evoluti di Ordinamento. Algoritmi che offrono una complessità computazionale proporzionale a n*log2n (che è sempre inferiore a n2) . Tali algoritmi sono molto più complessi, fanno molto spesso uso di ricorsione. La convenienza del loro utilizzo si ha unicamente quando il numero n di informazioni da ordinare è molto elevato. Si distinguono i metodi di ordinamento diretti o indiretti Un metodo di ordinamento si dice diretto se accede all’intero record del dato da confrontare, indiretto se utilizza dei riferimenti (puntatori) per accedervi Metodi indiretti sono utili quando si devono ordinare dati di grandi dimensioni in questo modo non è necessario spostare i dati in memoria ma solo i puntatori ad essi. Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 3 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 4 Algoritmi semplici di ordinamento Algoritmo per scambio Ordinamento per scambio Algoritmo tradizionale di ordinamento: Ordinamento per selezione (selection sort) 1. Confronta il primo elemento con i successivi, effettuando uno scambio di posizione quando l’ordine dei due elementi non è corretto Ordinamento per inserimento (insertion sort) 2. Alla fine del ciclo ne parte un altro che ripete la stessa operazione a partire dal suo adiacente (p.e. secondo elemento) e cosi’ via Ordinamento a bolle (bubblesort) Ordinamento shell 12 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 5 Algoritmo per scambio 24 3 10 35 Fondamenti di Informatica A.A. 2012-2013 41 2 71 a cura di Pascoschi Giovanni 6 Algoritmo per selezione (selection sort) void scambio(int A[ ], int n) { 1. L’algoritmo selection sort seleziona l’elemento minore (maggiore) del sottovettore e mettendolo al primo posto int i,j; for(i=0; i<n-1; i++) { for(j=i+1; i<n; i++) { if (A[i] > A[j]) { swap(A[i], A[j]); } } } 2. Si procede applicando lo stesso procedimento al sottovettore non ordinato e cosi’ via } 12 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 7 24 3 10 Fondamenti di Informatica A.A. 2012-2013 35 41 2 71 a cura di Pascoschi Giovanni 8 Algoritmo per selezione Algoritmo per inserimento L’algoritmo per inserimento consiste nell’inserire un elemento alla volta nella posizione che gli spetta in un vettore già ordinato, partendo dal vettore vuoto void scambio(int A[ ], int n) { int i, j, indicemin; for(i=0; i<n-1; i++) { indicemin = i; for(j=i+1; i<n; i++) { if (A[j] < A[indicemin]) indicemin = j; } swap(A[i], A[indicemin]); } 12 10 35 41 2 71 12 24 3 12 24 3 10 12 24 3 10 12 24 35 3 10 12 24 35 41 2 3 10 12 24 35 41 2 3 10 12 24 35 41 // nuova pos. minore a cura di Pascoschi Giovanni 9 Algoritmo per inserimento Fondamenti di Informatica A.A. 2012-2013 71 a cura di Pascoschi Giovanni 10 Algoritmo bubblesort L’algoritmo bubblesort consiste nel confrontare ogni elemento con il successivo. Se gli elementi non sono ordinati si scambiano i valori, e cosi’ via. void scambio(int A[ ], int n) { int i, j, value; // obiettivo posizionare A[i] for(i=0; i<n; i++) { // i identifica il sottovettore serie[0]-serie[i] value = A[i]; // A[i] temporaneamente salvato in value j = i; // j attraversa serie[j] cercando la pos. corretta while( j>0 && value < A[j-1]) { A[j] = A[j-1]; //sposta gli elementi a destra j--; } A[j] = value; } 1.Il valore piu’ piccolo (o piu’ grande) affiorerà come una bolla in un liquido } Fondamenti di Informatica A.A. 2012-2013 3 12 // posizione del minore } Fondamenti di Informatica A.A. 2012-2013 24 a cura di Pascoschi Giovanni 11 12 24 3 10 35 41 2 71 12 3 10 24 35 2 41 71 3 10 12 24 2 35 41 71 3 10 12 2 24 35 41 71 3 10 2 12 24 35 41 71 3 2 10 12 24 35 41 71 2 3 10 12 24 35 41 71 2 3 10 12 24 35 41 71 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 12 Algoritmo bubblesort Algoritmo shell void bubblesort(int A[ ], int n) { L’algoritmo shell è un ordinamento per inserimento con incrementi decrescenti (misto tra inserimento e bubble) int i; bool swapped; do { swapped=false; for(i=0; i<n-1; i++) { if (A[i]>A[i+1]) { swap(A[i], A[i+1]); swapped=true; } } } while(swapped); La lentezza dell'ordinamento per inserzione e' dovuta al fatto che le operazioni di scambio avvengono tra elementi adiacenti. Se l'elemento piu' piccolo e' alla fine dell'array ci vogliono N passi per disporlo al posto giusto L'idea dello shell sort e' di scambiare gli elementi prima molto distanti tra loro e poi progressivamente quelli piu' vicini } Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 13 Algoritmo shell Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 14 Algoritmo shell (esempio) 1.Si divide il vettore di n elementi in n/2 gruppi di due elementi, con un intervallo di n/2 e si ordina ciascun gruppo 20 12 5 31 24 35 1 14 2.Si divide il vettore in n/4 gruppi di quattro elementi con salto n/4 e si ordinano i singoli gruppi separatamente 20 12 1 14 24 35 5 31 1 12 5 14 20 31 24 35 3.Si ripete il processo finchè non si arriva all’ultimo passo con l’ordinamento di n gruppi ciascuno di 1 elemento (in questo passo il metodo coincide con il metodo a bolle) 1 5 12 14 20 24 31 35 1 5 12 14 20 24 31 35 4.Se si eseguono piu' passate ordinando l'array prima con passo “salto” grande e poi decrementandolo fino a passo 1 si ottiene un array via via sempre piu' ordinato fino ad averlo del tutto ordinato Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 15 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 16 Algoritmo shell (esempio) Algoritmo evoluto di ordinamento : Quicksort void ord_shell(int A[ ], int n) { int i, j, salto = n/2; while( salto >0 ) { for(i=salto; i<n; i++) { // ordinamento parziale di i vettori:i indice vettori j = i – salto; // gli elementi stanno a distanza salto while( j >= 0) { k = j + salto; // k e j indici degli elementi da confrontare if( A[j] <= A[k]) j= -1; // elementi contigui j e k del vettore fine ciclo else { swap(A[j], A[k]); j = j – salto; } } } salto = salto /2; } Si consideri un vettore di n elementi e lo si ordini con algoritmi semplici, con un tempo di calcolo proporzionale a n2. Si supponga, invece di dividere il vettore da ordinare in due sottovettori di n/2 elementi ciascuno e di ordinare le due metà separatamente. Applicando sempre gli algoritmi non evoluti, si avrebbe un tempo di calcolo pari a (n/2)2 + (n/2)2=n2/2. Se riunendo i due sottovettori ordinati si potesse riottenere il vettore originario tutto ordinato avremmo dimezzato il tempo di calcolo Se questo ragionamento si potesse applicare anche immaginando una decomposizione del vettore originario in quattro, si avrebbe un tempo di calcolo totale pari a: (n/4)2 + (n/4)2 + (n/4)2 + (n/4)2=n2/4. Se si potesse dividere in 8, si avrebbe un tempo ancora più basso, e così via. } Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 17 Algoritmo Quicksort Problema Supponiamo di dividere il vettore A a metà e di ordinare i due pezzi, separatamente ottenendo i due vettori A1 e A2. Il vettore ricomposto non è però ordinato. Il vincolo da porre è chiaro: possiamo applicare questo metodo solo se il massimo elemento in A1 è inferiore o uguale al minimo elemento di A2. L’operazione che crea due parti con la suddetta caratteristica si dice partizionamento del vettore. Fondamenti di Informatica A.A. 2012-2013 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 18 Algoritmo Quicksort 18 12 1 55 22 17 25 19 39 44 0 1 3 5 7 9 2 4 6 8 1. 2. Vett A 1 12 0 1 18 22 55 17 19 25 39 44 2 3 4 0 Vett A1 1 2 3 3. 4. 4 Vett A2 1 12 18 22 55 17 19 25 39 44 0 1 2 3 4 5 6 7 8 5. 9 6. 7. Utilizzo di un pivot centrale a cura di Pascoschi Giovanni 19 il vettore da ordinare viene delimitato dall'indice del primo elemento (inf) e dall'indice dell'ultimo elemento (sup). viene scelto un elemento del vettore di indice compreso tra inf e sup, chiamato pivot, scelto del tutto casualmente. Potrebbe essere l'elemento di indice (inf+sup)/2. vengono utilizzati due indici i, j che vengono inizializzati a i=inf e j=sup. l'indice i viene incrementato di 1 fino a quando l'elemento di indice i non è maggiore o uguale al pivot. l'indice j viene decrementato di 1 fino a quando l'elemento di indice j non è minore o uguale al pivot. nel caso in cui i < j, gli elementi di indici i e j vengono scambiati, e poi i viene incrementato e j decrementato (in modo unitario) nel caso in cui i = j, non si effettua lo scambio, ma i viene incrementato di 1 e j viene decrementato di 1 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 20 Algoritmo Quicksort Algoritmo Quicksort 8. se i >j (i due indici si sono “incrociati”) allora la fase di partizionamento termina. In questo modo risulta che: tutti gli elementi di indice appartenente a inf,..,j sono minori o uguali del pivot tutti gli elementi di indice appartenente a i,..,sup sono maggiori o uguali del pivot tutti gli elementi di indice appartenente a j+1,..,i-1 sono uguali al pivot 9. l'algortimo QuickSort viene applicato ricorsivamente al sottovettore individuato dagli indici (inf,j), se tale sottovettore contiene almeno un elemento, ossia se inf < j 10. l'algortimo QuickSort viene applicato ricorsivamente al sottovettore individuato dagli indici (i,sup), se tale sottovettore contiene almeno un elemento, ossia se i < sup Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 12 Fondamenti di Informatica A.A. 2012-2013 3 51 41 2 71 j=sup 2 24 3 10 51 41 12 71 2 10 3 24 51 41 12 71 quick 21 10 pivot i=inf Algoritmo Quicksort void QSort (int A[ ], int inf, int sup) { int pivot; int i,j; pivot = A[(inf+sup)/2]; i=inf; j=sup; do { while (A[ i ] < pivot) i++; while (A[ j ] > pivot) j- -; if (i<j) swap(A[i], A[j]); if (i<=j) { i++; j--; } } while (i<=j); if (inf<j) QSort(A,inf,j); if (i<sup) QSort(A,i,sup); } 24 Fondamenti di Informatica A.A. 2012-2013 quick a cura di Pascoschi Giovanni 22 Algoritmo Quicksort Caso migliore: il caso in cui il vettore originario è decomposto nella prima passata in due sottovettori di dimensione uguale. Il pivot viene scelto pari esattamente al valore mediano degli elementi contenuti nel vettore // ciclo per effettuare il partizionamento // trova A[i] >= pivot // trova A[j] <= pivot Caso peggiore: il vettore originario è decomposto in due sottovettori, di cui il primo ha dimensione uguale alla dimensione originaria meno 1, e l’altro ha una dimensione unitaria. Il pivot coincide con l’elemento massimo del vettore. // si ripete finche’ il partizionamento termina a cura di Pascoschi Giovanni 23 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 24 Riepilogo della lezione Fine della lezione Algoritmi di ordinamento in C++ Ordinamento per scambio Ordinamento per selezione (selection sort) Ordinamento per inserimento (insertion sort) Ordinamento a bolle (bubblesort) Ordinamento shell Ordinamento Quicksort Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni Domande? 25 Fondamenti di Informatica A.A. 2012-2013 a cura di Pascoschi Giovanni 26