ALGORITMI DI ORDINAMENTO • Scopo: ordinare una sequenza di elementi in base a una certa relazione d’ordine – lo scopo finale è ben definito → algoritmi equivalenti – diversi algoritmi possono avere efficienza assai diversa • Ipotesi: gli elementi siano memorizzati in un array. ALGORITMI DI ORDINAMENTO Principali algoritmi di ordinamento: • • • • • • naïve sort (semplice, intuitivo, poco efficiente) bubble sort (semplice, un po’ più efficiente) shell sort (generalizza bubble, efficienza media) insert sort (intuitivo, abbastanza efficiente) quick sort (non intuitivo, alquanto efficiente) merge sort (non intuitivo, molto efficiente) Ci concentreremo su quelli evidenziati. ISTRUZIONI DOMINANTI ALCUNI ALGORITMI SIGNIFICATIVI • Negli algoritmi di ordinamento di un array e di ricerca di un elemento in un array, l’istruzione dominante è il confronto fra elementi. Ordinamento di un array • naive sort l'algoritmo più semplice, il primo che Esempio: ricerca di un elemento in un array di interi boolean ricerca (int v[], int el){ int i=0; boolean trovato = false; while (i<N) { istruzioni dominanti if (el == v[i]) trovato = true; i++; N+1 confronti nel while } N confronti nell’ if return trovato; → costo lineare O(N) } NAÏVE SORT Specifica (sia n la dimensione dell’array v) while (<array non vuoto>) { <trova la posizione p del massimo> if (p<n-1) <scambia v[n-1] e v[p] > /* così v[n-1] contiene sempre il massimo */ <restringi l’attenzione alle prime n-1 caselle dell’ array, ponendo n’ = n-1 > } viene in mente… ma anche il meno efficiente • bubble sort un algoritmo ancora abbastanza semplice, un po' più efficiente del precedente nel caso medio (non nel caso peggiore) Ricerca in un array ordinato • ricerca binaria un algoritmo semplice ma molto efficiente, che sfrutta l'ipotesi di array ordinato NAÏVE SORT Codifica in C (o Java) void naiveSort(int v[], int n){ int p; La dimensione dell’array cala di 1 a ogni giro while (n>1) { p = trovaPosMax(v,n); if (p<n-1) /* scambia elementi */ { int t=v[p]; v[p]=v[n-1]; v[n-1]=t; } n--; } } 1 NAÏVE SORT NAÏVE SORT Codifica in C (o Java) int trovaPosMax(int v[], int n){ int i, posMax=0; All’inizio si assume v[0] come max di tentativo. for (i=1; i<n; i++) if (v[posMax]<v[i]) posMax=i; return posMax; } Valutazione di complessità • Il numero di confronti necessari vale sempre: (N-1) + (N-2) + (N-3) + … + 2 + 1 = = N*(N-1)/2 = O(N2/2) • Importante: – l’algoritmo fa gli stessi confronti sia per un array disordinato, sia per un array già ordinato!! Si scandisce l’array e, se si trova un elemento maggiore del max attuale, lo si assume come nuovo max, memorizzandone la posizione. BUBBLE SORT BUBBLE SORT • Corregge il difetto principale del naïve sort: quello di non accorgersi se l’array, a un certo punto, è già ordinato. • Corregge il difetto principale del naïve sort: quello di non accorgersi se l’array, a un certo punto, è già ordinato. Può accadere anche alla prima • Opera per “passate successive” sull’array: “passata”, se l’array è già ordinato • Opera per “passate successive” sull’array: – a ogni “passata”, considera una ad una tutte le possibili coppie di elementi adiacenti, scambiandoli se risultano nell’ordine errato – così, dopo ogni passata, l’elemento massimo è in fondo alla parte di array considerata – a ogni “passata”, considera una ad una tutte le possibili coppie di elementi adiacenti, scambiandoli se risultano nell’ordine Accorgendosi di array già ordinati, errato evita lavoro inutile. –l’algoritmo così, dopo ogni passata, l’elemento massimo è in fondo alla parte di array considerata • Quando non si verificano scambi, l’array è ordinato, e l’algoritmo termina. • Quando non si verificano scambi, l’array è ordinato, e l’algoritmo termina. BUBBLE SORT BUBBLE SORT Esempio Codifica void bubbleSort(int v[], int n){ int i; boolean ordinato = false; while (n>1 && !ordinato){ Continua solo se ordinato = true; l’array non è ancora for (i=0; i<n-1; i++) ordinato. if (v[i]>v[i+1]) { int t=v[i]; v[i]=v[i+1]; v[i+1]=t; ordinato = false; } n--; A ogni iterazione ipotizza che l’array sia ordinato, } poi verifica: se si deve fare anche solo uno } scambio, non era vero. Iª passata (dim. = 4) al termine, 7 è a posto. IIª passata (dim. = 3) al termine, 6 è a posto. IIIª passata (dim. = 2) al termine, 4 è a posto. array ordinato 2 RIFERIMENTI Alcuni link a cui si trovano algoritmi di ordinamento e relative animazioni: • sis.bris.ac.uk/~je7796/tech/sort.htm • www.cs.brockport.edu/cs/javasort.html In Java, esiste una classe standard che fornisce quicksort per array di ogni tipo: • package java.util, classe Arrays ALGORITMI DI RICERCA Cercare un elemento in un array: • in generale, richiede di controllare tutti gli elementi (fino a che non si trova l’elemento, o l'array è finito) • se però l'array è ordinato, la ricerca può essere svolta in modo molto più efficiente, sfruttando l’ordinamento per “andare a colpo sicuro” a cercare l’elemento richiesto. • metodo sort() (overloaded, molte versioni) RICERCA BINARIA • L’algoritmo emula ciò che si fa quando si cerca, a mano, una parola in un dizionario: si apre il dizionario “nella prima o nella seconda metà”, secondo l'iniziale della parola da cercare • Si confronta l’elemento da cercare con quello di posizione mediana nell’array. Così: • o l’elemento viene trovato subito • oppure si sa dove continuare la ricerca • a sinistra (fra gli elementi minori), se l’elemento mediano è maggiore di quello richiesto • a destra (fra gli elementi maggiori) in caso contrario. RICERCA BINARIA • La ricerca binaria consente di eliminare ad ogni passo metà degli elementi del vettore • Ricerca binaria di un elemento i in un vettore ordinato in senso non decrescente in cui il primo elemento è first e l’ultimo last • Si confronta l’elemento cercato el con quello mediano del vettore V[med] • Se el == V[med], fine della ricerca (trovato = true) RICERCA BINARIA 1) si confronta l’elemento da cercare con quello di posizione mediana 2) se è l’elemento cercato, la ricerca si conclude con successo -- altrimenti la ricerca prosegue • nella metà di sinistra dell’array se l’elemento mediano è maggiore di quello richiesto • nella metà di destra dell’array se l’elemento mediano è minore di quello richiesto. RICERCA BINARIA • Altrimenti, se il vettore ha almeno due componenti (first < last): – se el < V[med], ripeti la ricerca nella prima metà del vettore (indici da first a med-1); – se el > V[med], ripeti la ricerca nella seconda metà del vettore (indici da med-1 a last) • Numero di confronti: O(log2 N) 3 RICERCA BINARIA Esempio 4