6/11/01Ordinamento 1 Un esempio di algoritmi: ordinamento
6/11/01 Ordinamento2 Dati primitivi: ordinamento Un insieme di dati di tipo primitivo {a 1, a 2, a 3, …, a n } si dice ordinato se si ha a 1 a 2 a 3 … a n I dati sono generalmente memorizzati in vettori. public class SortVoti { static public void main(String[] args) { int [] voti = {20, 18, 30, 27, 26, 19, 21}; Sorts.selectionSort(voti); for(int i=0; i<voti.length; i++) System.out.println(voti[i] + “ “); }
6/11/01 Ordinamento3 Selezione diretta public class Sorts{ // // Ordina l’array di interi specificato usando l’algoritmo di selezione diretta. // public static void selectionSort (int[] numbers){ int min, temp; for (int index = 0; index < numbers.length-1; index++) { min = index; for (int scan = index+1; scan < numbers.length; scan++) if (numbers[scan] < numbers[min]) min = scan; // Swap the values temp = numbers[min]; numbers[min] = numbers[index]; numbers[index] = temp; }
6/11/01 Ordinamento4 Inserimento diretto // // Sorts the specified array of integers using the insertion // sort algorithm. // public static void insertionSort (int[] numbers){ for (int index = 1; index < numbers.length; index++){ int key = numbers[index]; int position = index; // shift larger values to the right while (position > 0 && numbers[position-1] > key){ numbers[position] = numbers[position-1]; position--; } numbers[position] = key; }
6/11/01 Ordinamento5 Dati ordinati Un insieme di dati {a 1, a 2, a 3, …, a n } si dice ordinato se, data una funzione f(.), si ha f(a 1 ) f(a 2 ) f(a 3 ) f(a n ) Nel caso di dati complessi (strutture o classi) normalmente la funzione corrisponde semplicemente con un valore particolare chiamato chiave (key) Spesso è utile definire un metodo specifico per confrontare fra loro i dati I dati sono generalmente rappresentati da oggetti memorizzati in vettori. 1.public class Dato { 2. 3.private int key; 4.private Object info; // restituisce vero se il parametro è >= al dato corrente 7.public boolean confronta(Dato a) { 8.return a.key >= key; 9.} // altre definizioni 12.}
6/11/01 Ordinamento6 Dati ordinati Data la definizione precedente si può definire un semplice metodo per verificare se un vettore è ordinato 1.public class Dato { // precedenti definizioni 4. 5.static boolean ordinato(Dato[] v) { 6.for(int i=0; i<v.length-1; i++) { 7.if(! v[i].confronta(v[i+1])) 8.return false; 9.} 10.return true; 11.} // altre definizioni 14.}
6/11/01 Ordinamento7 Dati ordinati 1.public class Dato { // precedenti definizioni 4. // due esempi di costruttori 5.public Dato() { 6.key = (int) (Math.random()*100); 7.} 8.public Dato(int chiave) { 9.key = chiave; 10.} static public void main(String[] args) { 13.Dato[] v = new Dato[10]; 14.for(int i=0; i<10; i++) v[i] = new Dato(); 15.System.out.println(Dato.ordinato(v)); 16.for(int i=0; i<10; i++) v[i] = new Dato(i); 17.System.out.println(Dato.ordinato(v)); 18.} } false true
6/11/01 Ordinamento8 Un primo esempio di ordinamento inde x <N- 1 index=0 Trova la posizione (min) del minimo degli elementi nelle ultime N-index posizioni Scambia gli elementi in posizione min ed index incrementa index Il vettore è ordinato Un vettore di lunghezza 1 è ordinato L’algoritmo si base sulla ricerca del minimo, una volta trovato lo si sposta nella posizione corretta falso vero
6/11/01 Ordinamento9 Il codice 1.public class Dato { 2. // precedenti definizioni 3.public static void selectionSort (Dato[] v) { 4. int min; 5. Dato temp; 6. for (int index = 0; index < v.length-1; index++) { 7. min = index; 8. for (int scan = index+1; scan < v.length; scan++) 9. if (v[scan].confronta(v[min])) 10. min = scan; 11. temp = v[min]; 12. v[min] = v[index]; 13. v[index] = temp; 14. } 15. } 16.// … 17.} Se v[scan].key < v[min].key allora aggiorno min
6/11/01 Ordinamento10 Il codice 1.public class Dato { // precedenti definizioni static public void main(String[] args) { 6.Dato[] v = new Dato[10]; 7.for(int i=0; i<10; i++) v[i] = new Dato(); 8.System.out.println(Dato.ordinato(v)); 9.Dato. selectionSort (v); 10.System.out.println(Dato.ordinato(v)); 11.} } false true
6/11/01 Ordinamento11 Commenti sul metodo Dato un vettore di N elementi, l’algoritmo richiede un ciclo di N-1 passi Al ciclo i-esimo la ricerca del minimo richiede N-i confronti Al termine del ciclo si effettua uno scambio fra dati Complessivamente si fanno N(N-1)/2 confronti e (N-1) scambi Il tempo di esecuzione dell’algoritmo cresce con il quadrato della dimensione Si noti che il numero di confronti non cambia anche quando il vettore è già ordinato
6/11/01 Ordinamento12 Inserimento diretto inde x < N index = 1 Trova la posizione corretta dell’elemento in posizione index scandendo gli elementi precedenti Sposta gli elementi piu’ grandi a destra incrementa index Il vettore è ordinato È il metodo normalmente utilizzato dai giocatori di carte falso vero Copia l’elemento nella posizione corretta
6/11/01 Ordinamento13 Esempio di esecuzione
6/11/01 Ordinamento14 Il codice 1.public class Dato { // precedenti definizioni 4. 5.static void insertionSort(Dato[] v) { 6.for (int index = 1; index < v.length; index++){ 7. Dato key = v[index]; 8. int position = index; 9. // shift larger values to the right 10. while (position > 0 && !v[position- 1].confronta(key)){ 11. v[position] = v[position-1]; 12. position--; 13. } 14. v[position] = key; 15.} 16.// … 17.} Se v[position-1].key > v[index].key allora sposto v[position-1] a destra
6/11/01 Ordinamento15 Commenti sul metodo Dato un vettore di N elementi, l’algoritmo richiede un ciclo di N-1 passi Al ciclo i-esimo la ricerca della posizione richiede mediamente i/2 confronti e spostamenti fra dati dati Complessivamente anche in questo caso il tempo di esecuzione dell’algoritmo cresce con il quadrato della dimensione Si noti che il numero di operazioni diminuisce drasticamente in caso di vettore ordinato
6/11/01 Ordinamento16 Bubblesort Ad ogni ciclo un elemento “risale” fino a che è possibile
6/11/01 Ordinamento17 Il codice 1.public class Dato { // precedenti definizioni static void bubbleSort(Dato[] v) 6. { 7. boolean flag=true; 8. for(int i=0; i<v.length-1 && flag; i++) { 9.flag = false; 10.for(int j=v.length-1; j>i; j--) { 11. if(!v[j-1].confronta(v[j])) { 12.flag = true; 13.Dato tmp = v[j-1]; 14.v[j-1] = v[j]; 15.v[j] = tmp; 16. } 17.} 18. } 19. } 20. // … 21.} Se v[j-1].key > v[j].key allora effettuo lo scambio e aggiorno flag
6/11/01 Ordinamento18 Commenti sul metodo Dato un vettore di N elementi, l’algoritmo richiede un ciclo di N-1 passi Al ciclo i-esimo la ricerca della posizione richiede N-i confronti e un numero variabile di scambi Complessivamente anche in questo caso il tempo di esecuzione dell’algoritmo cresce con il quadrato della dimensione Si termina non appena non si fanno più scambi (flag = false)
6/11/01 Ordinamento19 Ordinamento per partizione Il metodo è chiamato quicksort perché è veloce: il tempo di esecuzione in questo caso è N*log(N) decisamente inferiore per vettori di grosse dimensioni Ad ogni passo si sceglie un elemento e si divide il vettore in due parti che contengono tutti i valori minori o uguali da una parte e maggiori o uguali dall’altra
6/11/01 Ordinamento20 Il codice 1.public class Dato { 2. // precedenti definizioni 3.static void ordina(Dato[] v) { 4.quicksort(v, 0, v.length-1); 5.} 6.static void quicksort(Dato[] v, int s, int d) { 7.Dato p = v[(s+d)/2]; 8.int i=s, j=d; 9.do { // !(v[i].key>=p.key) v[i].key<p.key 10.while(!p.confronta(v[i])) i++; 11.while(!v[j].confronta(p)) j--; 12.if(i<=j) { 13.Dato tmp = v[i]; 14.v[i] = v[j]; 15.v[j] = tmp; 16.i++; j--; 17.} 18.} while(i<=j); 19.if(s<j) quicksort(v, s, j); 20.if(i<d) quicksort(v, i, d); 21.} // … 22.}
6/11/01 Ordinamento21 Fusione Dati due insiemi ordinati Ad ogni passo si estrae l’elemento più piccolo – è sufficiente un singolo confronto
6/11/01 Ordinamento22 Fusione È sufficiente un numero di operazioni proporzionale al numero complessivo di dati È però necessario un secondo vettore di destinazione 1.static void merge(Dato[] a, Dato[] b, Dato[] ris) { 2. int i = 0, j = 0, k = 0; 3. while(i<a.length && j<b.length) { 4. if(a[i].confronta(b[j])) { 5. ris[k++] = a[i++]; 6. } else { 7. ris[k++] = b[j++]; 8. } 9. } 10. while(i<a.length) ris[k++] = a[i++]; 13. while(j<b.length) 14. ris[k++] = b[j++]; 15.}