ALGORITMI DI ORDINAMENTO
Cinzia Reverberi
COS’È UN ALGORITMO?
Un algoritmo è un insieme ben ordinato di operazioni non ambigue ed
effettivamente calcolabili che, eseguito, produce un risultato e termina in
una quantità finita di tempo.
In pratica, i punti principali di un algoritmo sono:
-un insieme ben ordinato di operazioni
-operazioni non ambigue e calcolabili
-produce un risultato
-termina in una quantità finita di tempo
ALGORITMO DI ORDINAMENTO
E’ un algoritmo che viene utilizzato per elencare gli elementi di un insieme secondo una sequenza
stabilita da una relazione d’ordine.
Vi sono numerosi tipi di algoritmi di ordinamento:
-quelli più semplici, iterativi:
* insertion sort
* selection sort
* bubble sort
-applicabili solo in casi particolari:
* counting sort
* radix sort
* bin o bucket sort
-più complessi, ricorsivi:
* merge sort
* quicksort
* heapsort
INSERTION SORT

È un algoritmo relativamente semplice che si occupa di ordinare un array.
Esso si occupa di ciò senza l’utilizzo di un array di appoggio (algoritmo in
place).

L’algoritmo tende a spostare gli elementi maggiori verso destra: utilizza due
indici. Il primo punta al secondo elemento dell’array, mentre il secondo
punta al primo. Se il primo elemento è maggiore del secondo i due elementi
vengono scambiati e successivamente il primo indice avanza di una posizione
mentre il secondo parte da quello precedentemente puntato dal primo.
#include <stdlib.h>
#include <stdio.h>
#define MAX 100
/* * Legge in input il numero n ed n numeri interi * che memorizza nell'array. Restituisce il numero * di elementi letti (n). */
int leggi_array(int x[ ]) { int i, n; printf("Numero di elementi: ");
scanf("%d", &n);
printf("Inserisci %d elementi: ", n)
; for (i=0; i<n; i++)
scanf("%d", &x[i]); return(n); }
/* * Stampa in output l'array. *
void stampa_array(int x[ ], int n) {
int i;
for (i=0; i<n; i++)
printf("%d ", x[i]);
printf("\n");
return;
}
/* * Funzione che implementa l'algoritmo Insertion sort. * Riceve come argomento l'array ed il numero di * elementi contenuti nell'array. Non restituisce alcun * valore, ma
modifica il contenuto dell'array, ordinandolo. */
void insertion_sort (int x[ ], int n) {
int i, j, app; for (i=1; i<n; i++) {
app = x[i];
j = i-1; while (j>=0 && x[j]>app) {
x[j+1] = x[j]; j--; }
x[j+1] = app; }
return; } /* * Funzione principale */
int main(void)
{ int v[MAX], n; n = leggi_array(v);
stampa_array(v, n);
insertion_sort(v, n);
stampa_array(v, n);
return(1); }
SELECTION SORT

Come l’algoritmo precedente, opera in place.

I passi che compie l’algoritmo per ordinare l’array sono i seguenti:
- si inizializza un puntatore i che va da 1 a n (dove n è la lunghezza
dell'array).
-Si cerca il più piccolo elemento dell'array
-Scambia l'elemento più piccolo con l'elemento alla posizione i
-Incrementa l'indice i e si torna al passo uno fino alla fine dell'array.
/* SELECTION SORT Ricerca il minimo nella parte di array non ancora ordinata e lo ordina. Poi prosegue con altre ricerche
ripetute nella parte di array non ancora ordinata. */
void selection_sort(int a[], int n) { //funzione tipo void, effettua modifiche permanenti e non restituisce nulla
. int min = a[0], i = 0, j, p = 0; //dichiariamo il minimo dell'array uguale alla sua prima
componente.
while (i < n) { //scansioniamo tutto l'array
for (j = i; j < n; j++){ //scansiona tutto l'array partendo da una posizione in più poichè uscendo da qua 1 elemento sarà già
ordinato.
if (a[j] < min) { //se l'elemento attuale è minore del minimo allora l'elemento attuale sarà il nuovo minimo
min = a[j];
p = j; //memorizziamo la posizione del minimo nell'array } }
scambia (&a[i],&a[p]); //uscendo dal ciclo for scambiamo di posizione l'elemento iniziale della scansione con il minimo
trovato.
i++; //incrementiamo i per passare a scansionare il restante array non ancora ordinato. min = a[i]; //settiamo il minimo
uguale all'elemento dopo.
}
}

BUBBLE SORT

È un semplice algoritmo di ordinamento. Può essere utilizzato per ordinare
tutti i tipi di elementi su cui sia definita una relazione d’ordine.

Il suo nome deriva dal fatto che durante il suo procedimento ci sono dati che
si muovono nell’array velocemente e altri che lo fanno più lentamente. Ciò
ricorda il movimento delle bollicine in un bicchiere di champagne.
/* BUBBLESORT - Ordinamento di un Array. */
void bubblesort (int a[], int n) { int i, j; // N.B. n-1 è l'ultima componente dell'array.
for(i = 0; i < n - 1; i++) //scansiona tutto l'array tranne l'ultima componente: n - 1 escluso. Quindi fino al penultimo
elemento.
for (j = n - 1; j > i; j--) //j settato all'ultima componente e decresce ad ogni iterazione. Esce dal ciclo solo se j <= i
if (a[j] < a[j-1]) //se la componente corrente è più piccola della precedente, li scambia.
scambia(&a[j],&a[j-1]);
}
//la funzione scambia è così composta:
void scambia(int *a, int *b) { //richiede due indirizzi di memoria in entrata che verranno memorizzati in 2
puntatori.
int temp; //la variabile d'appoggio che memorizza temporaneamente il valore di a.
temp = *a;
*a = *b;
*b = temp; } //NB. l'asterisco * dei puntatori fa riferimento sempre al valore a cui punta il puntatore.
COUNTING SORT

Algoritmo di ordinamento per valori numerici interi

L'algoritmo è semplice ed intuitivo: si calcolano i valori max(A) e min (A) e
si prepara un array C di dimensione pari all'intervallo dei valori con C[i] che
rappresenta la frequenza dell'elemento i+min(A) nell'array di partenza A. Si
visita l'array A aumentando l'elemento di C corrispondente. Dopo si visita
l'array C in ordine e si scrivono su A, C[i] copie del valore i+min(A).
RADIX SORT

è un algoritmo di ordinamento per valori numerici interi, dove l è la
lunghezza dell'array e m è la media del numero di cifre dei numeri.

Esegue gli ordinamenti per posizione della cifra ma partendo dalla cifra
meno significativa. Questo affinché l'algoritmo non si trovi a dovere operare
ricorsivamente su sottoproblemi di dimensione non valutabili a priori.
BUCKET SORT


è un algoritmo di ordinamento per valori numerici interi
si prepara un array C di dimensione pari a m (cioè al valore
massimo che può essere nell'array) con C[i] che rappresenta la
frequenza dell'elemento i nell'array di partenza A. Si visita
l'array A aumentando l'elemento di C corrispondente. Dopo si
visita l'array C in ordine e si scrivono su A, C[i] copie del valore
i.

#include <stdio.h>
void bucketSort(int array[], int n) {
int i, j;
int count[n];
for(i=0; i < n; i++) {
count[i] = 0;
}
for(i=0; i < n; i++) {
(count[array[i]])++;
}
for(i=0,j=0; i < n; i++) {
for(; count[i]>0; (count[i])--) {
array[j++] = i;
}
}
}
int main() {
int array[] = {1,3,4,6,4,2,9,1,2,9};
int n = 10;
int i;
for (i = 0;i < n;i++) {
printf("%d ", array[i]);
}
printf("\n");
bucketSort(array, n);
for (i = 0;i < n;i++) {
printf("%d ", array[i] );
}
printf("\n");
return 0;
}
MERGE SORT

consiste nella suddivisione del problema in sottoproblemi via
via più piccoli.

Il merge sort opera quindi dividendo l'insieme da ordinare in
due metà e procedendo all'ordinamento delle medesime
ricorsivamente. Quando si sono divise tutte le metà si procede
alla loro fusione (merge appunto) costruendo un insieme
ordinato
/* * Legge in input il numero n ed n numeri interi * che memorizza nell'array. Restituisce
il numero * di elementi letti (n). */
int leggi_array(int V[]) {
int n, i;
printf("Numero di elementi: ");
scanf("%d", &n);
for (i=0; i<n; i++)
scanf("%d", &V[i]); return(n);
}
/* * Stampa in output l'array. */
void stampa_array(int V[], int n) {
int i;
for (i=0; i<n; i++) {
printf("%d ", V[i]);
}
return; }
/* * Funzione Merge per la fusione di due * componenti ordinate dell'array. */
void Merge(int A[], int p, int q, int r) {
int i, j, k, B[MAX];
i = p;
j = q+1;
k = 0;
while (i<=q && j<=r) {
if (A[i]<A[j]) {
B[k] = A[i]; i++;
}
else {
B[k] = A[j]; j++;
}
k++; }
while (i<=q) {
B[k] = A[i];
i++;
k++; }
while (j<=r) {
B[k] = A[j];
j++;
k++; } f
or (k=p; k<=r; k++) A[k] = B[k-p]; return;
}
/* * Funzione ricorsiva MergeSort. */
void MergeSort(int A[], int p, int r) {
int q;
f (p<r) { q = (p+r)/2;
MergeSort(A, p, q);
MergeSort(A, q+1, r);
Merge(A, p, q, r); }
return; }
/* * Funzione principale */
int main(void) {
int n, V[MAX];
n = leggi_array(V);
MergeSort(V, 0, n-1);
stampa_array(V, n);
return(1); }
QUICKSORT
è
un ottimo algoritmo di ordinamento ricorsivo in
place
a
base del suo funzionamento è l'utilizzo ricorsivo
della procedura partition: preso un elemento da una
struttura dati (es. array) si pongono gli elementi
minori a sinistra rispetto a questo e gli elementi
maggiori a destra.
void scambia (tipobase v[], long i, long j)
{
tipobase tmp=v[i];
v[i]=v[j];
v[j]=tmp;
}
void QSort (tipobase v[], long inf, long sup)
{
tipobase pivot=v[(inf+sup)/2];
long i=inf,j=sup;
while (i<=j) {
while (v[i]<pivot) i++;
while (v[j]>pivot) j--;
if (i<j)
scambia(v,i,j);
if (i<=j) {
i++;
j--;
}
}
if (inf<j) QSort(v,inf,j);
if (i<sup) QSort(v,i,sup);
}
HEAPSORT
 basa
la sua potenza sull’utilizzo di una struttura dati
chiamata Heap, che gestisce intelligentemente le
informazioni durante l’esecuzione dell’algoritmo di
ordinamento.