Informatica
GLI ALGORITMI DI ORDINAMENTO
Un algoritmo si può definire come un procedimento che
consente di ottenere un risultato atteso eseguendo, in un
determinato ordine, un insieme di passi semplici
corrispondenti ad azioni scelte solitamente da un insieme
finito.
Da questa definizione si evincono le quattro proprietà
fondamentali dell'algoritmo:

la sequenza di istruzioni deve essere finita (finitezza);

essa deve portare ad un risultato (effettività);


le istruzioni devono essere eseguibili materialmente
(realizzabilità);
le istruzioni devono essere espresse in modo non ambiguo
(non ambiguità).




Un algoritmo di ordinamento è un algoritmo che viene
utilizzato per elencare gli elementi di un insieme secondo
una sequenza stabilita da una relazione d'ordine, in modo
che ogni elemento sia minore (o maggiore) di quello che lo
segue.
In assenza di altre specifiche, la relazione d'ordine viene
sempre considerata totale (cioè tale da rendere sempre
possibile il confronto tra due elementi dell'insieme).
A seconda del verso della relazione considerato, un
ordinamento può essere ascendente o discendente.
Per analizzare e studiare gli algoritmi di ordinamento sono
stati definiti differenti criteri di partizionamento, ne descrivo
i più importanti.

Ordinamento interno e ordinamento esterno
Se il file da ordinare, o la struttura dati, può essere contenuto
in memoria, il metodo viene detto interno. L'ordinamento di
file residenti su disco o su nastro viene chiamato ordinamento
esterno: la differenza principale tra i due tipi di ordinamento
sta nel fatto che mentre nel primo è possibile accedere
direttamente a un record, nel secondo i record devono essere
indirizzati in modo sequenziale o al più per grandi blocchi.

Ordinamento per confronti-scambi e digitale
A seconda del tipo di operazione che viene effettuata, si
hanno due differenti tipi di ordinamento. L'ordinamento che
effettua confronti e scambi e l'algoritmo digitale che accede
all'informazione tramite un gruppo di bit alla volta.

Ordinamento adattivo
Solitamente un algoritmo di ordinamento sfrutta operazioni di
confronto e scambio. Se tali operazioni vengono svolte in
modo indipendente dai dati di input l'algoritmo viene definito
non adattivo. Mentre se un metodo di ordinamento esegue
diverse sequenze di operazioni in funzione del risultato dei
confronti si ha un algoritmo adattivo.
Descrivo alcuni importanti algoritmi di ordinamento:
-Selection Sort
-Insertion Sort
-Quick Sort
-Merge Sort
-Bubble Sort
-Counting Sort
Insertion Sort
Si assume che la sequenza da ordinare sia partizionata in
una sottosequenza già ordinata, all'inizio composta da un
solo elemento, e una ancora da ordinare.
Alla k-esima iterazione, la sequenza già ordinata contiene k
elementi. In ogni iterazione, viene rimosso un elemento dalla
sottosequenza non ordinata e inserito nella posizione corretta
della sottosequenza ordinata, estendendola così di un
elemento.
3 2 5 1 4 considero il 2
2 3 5 1 4 considero il 5
2 3 5 1 4 considero il 1
1 2 3 5 4 considero il 4
12345
Selection Sort
L'algoritmo seleziona di volta in volta il numero minore nella
sequenza di partenza e lo sposta nella sequenza ordinata; di
fatto la sequenza viene suddivisa in due parti: la
sottosequenza ordinata, che occupa le prime posizioni
dell'array, e la sottosequenza da ordinare, che costituisce la
parte restante dell'array.
Dovendo ordinare un array A di lunghezza n, si fa scorrere
l'indice i da 1 a n-1 ripetendo i seguenti passi:
si cerca il più piccolo elemento della sottosequenza A[i..n];
si scambia questo elemento con l'elemento i-esimo.
Quick Sort
Quicksort è un algoritmo di ordinamento ricorsivo che, come
merge sort, si basa sul paradigma divide et impera. La 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.
L'idea base può esprimersi agevolmente in termini ricorsivi.
Ad ogni stadio si effettua un ordinamento parziale di una
sequenza di oggetti da ordinare. Assunto un elemento come
perno dello stadio, si confrontano con esso gli altri elementi e
si posizionano alla sua sinistra i minori e a destra i maggiori,
senza tener conto del loro ordine. Dopo questo stadio si ha
che il perno è nella sua posizione definitiva.

Esempio: 6 2 7 1 5 4 3
pivot 6
2154367
pivot 2
1254367
pivot 5
1243567
pivot 4
1234567
Merge Sort
L'algoritmo funziona nel seguente modo:
Se la sequenza da ordinare ha lunghezza 0 oppure 1, è già
ordinata. Altrimenti:
La sequenza viene divisa (divide) in due metà (se la
sequenza contiene un numero dispari di elementi, viene
divisa in due sottosequenze di cui la prima ha un elemento
in più della seconda)
Ognuna di queste sottosequenze viene ordinata, applicando
ricorsivamente l'algoritmo(impera)
Le due sottosequenze ordinate vengono fuse (combina). Per
fare questo, si estrae ripetutamente il minimo delle due
sottosequenze e lo si pone nella sequenza in uscita, che
risulterà ordinata

Esempio: [10 3 15 2 1 4 9 0]
[10 3 15 2]
[1 4 9 0]
[10 3] [15 2] [1 4] [9 0]
[3 10] [2 15] [1 4] [0 9]
[2 3 10 15] [0 1 4 9]
[0 1 2 3 4 9 10 15]
Bubble Sort
Il bubble sort è un algoritmo iterativo, ossia basato sulla
ripetizione di un procedimento fondamentale. La singola
iterazione dell'algoritmo prevede che gli elementi dell'array
siano confrontati a due a due, procedendo in un verso
stabilito (che si scorra l'array a partire dall'inizio in avanti, o a
partire dal fondo all'indietro, è irrilevante; nel seguito
ipotizzeremo che lo si scorra partendo dall'inizio).
Per esempio, saranno confrontati il primo e il secondo
elemento, poi il secondo e il terzo, poi il terzo e il quarto, e
così via fino al confronto fra il penultimo e l'ultimo elemento.
Ad ogni confronto, se i due elementi confrontati non sono
ordinati essi vengono scambiati. Durante ogni iterazione
almeno un valore viene spostato rapidamente fino a
raggiungere la sua collocazione definitiva; in particolare, alla
prima iterazione il numero più grande raggiunge l'ultima

Esempio : 15 6 4 10 11 2
6 15 4 10 11 2
6 4 15 10 11 2
6 4 10 15 11 2
6 4 10 11 15 2
6 4 10 11 2 15
4 6 10 11 2 15
4 6 10 2 11 15
4 6 2 10 11 15
4 2 6 10 11 15
2 4 6 10 11 15
Heap Sort
L'algoritmo che ordina in senso crescente inizia creando uno
heap decrescente. Per ogni iterazione si copia la radice
(primo elemento dell'array) in fondo all'array stesso,
eseguendo uno scambio di elementi. L'algoritmo poi
ricostruisce uno heap di elementi spostando verso il basso la
nuova radice, e ricomincia con un altro scambio (tra il primo
elemento dell'array e quello in posizione ), eseguendo un
ciclo che considera array di dimensione progressivamente
decrescente.
Counting sort
L'algoritmo conta il numero di occorrenze di ciascun valore
presente nell'array da ordinare, memorizzando questa
informazione in un array temporaneo di dimensione pari
all'intervallo di valori. Il numero di ripetizioni dei valori inferiori
indica la posizione del valore immediatamente successivo.
Si calcolano i valori massimo e minimo dell'array e si prepara
un array ausiliario C di dimensione pari all'intervallo dei valori
con C[i] che rappresenta la frequenza dell'elemento 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 .