ALGORITMI DI SORT Hanno come obiettivo l`ordinamento crescente

ALGORITMI DI SORT
Hanno come obiettivo l'ordinamento crescente o decrescente di un insieme di dati; uno dei casi più
interessanti riguarda l'ordinamento dei valori memorizzati in un vettore (numeri interi, reali,
stringhe). È importante sottolineare fin da subito che non esiste un algoritmo migliore in assoluto:
alcuni sono da preferire quando si sa che il vettore è già quasi ordinato (quindi con pochi elementi
fuori posto), altri quando invece il vettore è molto disordinato; alcuni è conveniente usarli con
vettori sufficientemente grandi perché si basano su tecniche più sofisticate che aggiungono dei
tempi che si ammortizzano solo se il numero di elementi è elevato. Alcuni sono particolarmente
veloci ma altrettanto voraci di RAM.
Qualunque sia l'algoritmo esso procede per confronti e scambi e l'algoritmo più veloce è quello che
ovviamente ne necessita di meno. Esistono molti algoritmi di sort ma qui di seguito ne prenderemo
in considerazione solo tre: bubble sort, selection sort e quick sort.
NOTA: ti ricordo che dal sito puoi scaricare una videolezione con la simulazione animata dei tre
tipi di sort.
BUBBLE SORT
Il vettore viene fatto scorrere da sinistra a destra (ordinamento crescente) tante volte quanti sono gli
elementi meno uno (l'ultimo che avanza sarà per forza nella posizione che gli compete); e ad ogni
passata un ciclo più interno confronta, sempre ripartendo dall'inizio, il primo elemento con il
secondo e nel caso li scambia, il secondo con il terzo e nel caso li scambia e così via fermandosi
ogni volta una posizione prima rispetto alla passata precedente (sequenza di confronti e scambi
effettuata dal ciclo interno). In questo modo ad ogni passata il maggiore dei numeri rimasti viene
spostato nella posizione più destra ancor da occupare emergendo come una bolla che procede verso
la superficie (da cui il nome dell'algoritmo).
void Bubblesort (int data[],int n) {
int tmp,i,j;
for (i=0; i<n-1; i++) {
for (j=0; j<n-i-1; j++)
if (data[j] > data[j+1]) {
tmp = data[j];
data[j] = data[j+1];
data[j+1] = tmp;
}
}
}
Questo algoritmo è molto semplice da codificare ma ha prestazioni accettabili solo per piccoli
vettori. Il numero di operazioni che compie (confronti più scambi) nel caso medio è nell'ordine di n2
dove n è il numero degli elementi del vettore.
SELECTION SORT
Procede per selezioni successive del minimo degli elementi che rimangono da ordinare. Alla prima
passata determina la posizione del minimo valore cercandolo in tutto il vettore; il minimo è quindi
messo in prima posizione ed il suo posto preso da quello che era in prima posizione. Poi cerca il
minimo elemento dalla seconda posizione all'ultima: il minimo viene poi messo in seconda
posizione. Si procede così fino che non si rimane con l'ultimo elemento che per forza di cose è già
al suo posto.
void selectionSort(int v[], int num_ele)
{
int temp=0;
for (int i=0; i<num_ele-1; i++)
{ int posMin = posMinimo(v, i, num_ele-1);
temp=v[i];
v[i]=v[posMin];
v[posMin] = temp;
}}
Il numero di operazioni che compie (confronti più scambi) nel caso medio è nell'ordine di n2 dove n
è il numero degli elementi del vettore.
QUICK SORT
È ancora oggi considerato probabilmente il più veloce ma è anche instabile (in alcune situazioni le
sue prestazioni possono decadere a livello dei peggiori algoritmi di sort). Inizialmente viene scelto
un elemento che divide, rispetto la sua posizione, il vettore in due parti (chiamiamo questo elemento
pivot, perno); con un ciclo procede poi a cercare partendo da sinistra il primo elemento di quella
metà che ha un valore maggiore del perno (che dovrebbe quindi nell'ordine stare alla destra del
perno e non alla sua sinistra come ora); poi si cerca partendo dal fondo il primo elemento nella parte
di destra per valore dovrebbe stare alla sinistra del pivot; i due elementi trovati vengono scambiati.
Se uno degli elementi (a sinistra o destra) non viene trovato lo scambio avviene con il pivot. Si
procede così fino a che la ricerca nella a parte a sinistra scavalca la ricerca nella parte a destra.
Dopo questa prima passata alla sinistra del pivot avrò tutti elementi più piccoli (non li avrei spostati
lì) di quelli quelli che si trovano alla destra del pivot. Il meccanismo si ripete lavorando
separatamente sulla parte di sinistra e quella di destra considerati come due vettori più piccoli da
ordinare. Il meccanismo è di tipo ricorsivo ed infatti l'implementazione del quick sort è di solito
sotto forma di una funzione ricorsiva.
Idealmente il pivot dovrebbe sempre avere un valore che è medio rispetto a quelli che si trovano
nella metà di sinistra e di destra. Nella realtà questo non avverrà sempre e se venisse scelto 'male'
per com'è la posizione degli elementi di partenza si avrebbe, come detto, un notevole scadimento
delle prestazioni.
Notiamo come rispetto al bubble sort dove gli scambi avvengono tra elementi adiacenti facendo
percorrere loro piccoli spostamenti di una posizione per volta nel quick sort con una singola
operazione di scambio possono essere spostati due elementi che stanno agli opposti del vettore.
void quick_sort(int arr[], int low, int high) {
int i = low;
int j = high;
int y = 0;
/* compare value */
int z = arr[(low + high) / 2];
/* partition */
do {
/* find member above ... */
while(arr[i] < z) i++;
/* find element below ... */
while(arr[j] > z) j--;
if(i <= j) {
/* swap two elements */
y = arr[i];
arr[i] = arr[j];
arr[j] = y;
i++;
j--;
}
} while(i <= j);
/* recurse */
if(low < j)
quick_sort(arr, low, j);
if(i < high)
quick_sort(arr, i, high);
}
Il numero di operazioni che compie (confronti più scambi) nel caso medio è nell'ordine di Nlog(N)
dove N è il numero degli elementi del vettore.