Laboratorio di Programmazione
Appunti sulla lezione 5:
Algoritmi di ordinamento (cont.)
Alessandra Raffaetà
Università Ca’ Foscari Venezia
Corso di Laurea in Informatica
Bubblesort
ƒ Idea: Due elementi adiacenti si scambiano
posizione in modo che quello più piccolo si sposti
verso l’inizio dell’array.
□ Ad ogni passaggio l’elemento più piccolo si muove da
destra a sinistra fluttuando come una bolla verso
l’inizio dell’array.
ƒ Ottimizzazione: Se in un passaggio non è stato
effettuato nessuno scambio l’array è ordinato.
Bubblesort
void bubblesort(TipoElem v[ ], int dim)
{ int i = 0, j, ordinato;
TipoElem temp;
do {
ordinato = 1;
for (j = dim – 1; j > i; j --)
if (maggiore(v[j - 1], v[j])) { /*elemento più piccolo galleggia verso l’alto*/
temp = v[j];
v[j] = v[j - 1];
v[j – 1] = temp;
ordinato = 0;
}
i++;
/* ordinato == 1 sse nessuno scambio è stato effettuato */
} while (i < dim – 1 && !ordinato);
}
Algoritmo di ordinamento: mergesort
ƒ Algoritmo di tipo divide et impera.
ƒ Divide: divide l’array v[p..u] in due sottoarray con
metà elementi, v[p..med] e v[med+1..u] dove med
= (p+u)/2.
ƒ Impera: ordina ricorsivamente i sottoarray
usando il mergesort se il sottoarray ha almeno
due elementi, altrimenti il sottoarray è ordinato.
ƒ Combina: fondi insieme i due sottoarray ordinati
v[p..med] e v[med+1..u] al fine di ottenere un
array ordinato v[p..u].
La procedura mergesort
void mergesort (TipoElem v[ ], int iniziale, int finale)
/*Ordina gli elementi del vettore v di indice compreso tra iniziale e
finale */
{ int med;
if (iniziale < finale) {
med = (iniziale + finale)/2;
mergesort(v, iniziale, med);
mergesort(v, med + 1, finale);
merge(v, iniziale, med, finale);
}
}
Esempio: le chiamate ricorsive di mergesort
1
8
3
2
0
1
2
3
1
8
3
2
0
1
2
3
5
7
4
5
4
9
6
7
5
7
4
1
8
3
2
0
1
2
3
5
4
5
7
4
9
6
7
4
9
6
7
5
1
8
3
2
5
7
4
9
0
1
2
3
4
5
6
7
La procedura merge
ƒ Idea: Da due mazzetti ordinati di carte vogliamo farne un
terzo mettendo di volta in volta la carta più piccola tra le
due in cima ai due mazzetti. Questo si ripete fino a
quando uno dei due mazzetti finisce. Le carte restanti
sono aggiunte in fondo.
void merge (TipoElem v [ ], int iniziale, int med, int finale)
/*Fonde i due sottoarray ordinati di v da iniziale a med e da med+1 a
finale in un unico sottoarray ordinato da iniziale a finale */
{ TipoElem buf [DIM];
int primo,secondo, appoggio,i;
primo = iniziale;
secondo = med +1;
appoggio = iniziale;
/* vettore di appoggio */
La procedura merge (cont.)
while (primo <= med && secondo <= finale) {
if (minoreUguale(v [primo], v [secondo])) {
buf [appoggio] = v [primo];
primo ++;
}
else {
buf [appoggio] = v [secondo];
secondo ++;
}
appoggio++;
}
La procedura merge (cont.)
if (secondo > finale)
/* è finito prima il secondo sottoarray;
copia da v in v stesso tutti gli elementi
fino a med, cominciando dal fondo */
for (i= med; i>=primo; i--) {
v[finale] = v[i];
finale --;
}
/* copia tutti gli elementi da iniziale a appoggio – 1 da buf a v */
for (i = iniziale; i < appoggio; i++)
v[i] = buf[i];
}
Come funziona la procedura merge
ƒ Primo ciclo: Finché le due sottosequenze sono non
vuote preleva l’elemento più piccolo in cima alle
sottosequenze.
ƒ Secondo ciclo: Disponi in posizione corretta gli
elementi rimasti nella prima sottosequenza se
non vuota.
□ Osservazione: se la sottosequenza vuota è la prima non
occorre fare alcuna operazione poiché gli elementi
sono già in posizione corretta in base all’ordinamento.
ƒ Terzo ciclo: Trasferisci gli elementi dal vettore
di appoggio nella posizione corrispondente nel
vettore di partenza.
Esempio di calcolo della procedura merge
1
8
3
2
5
7
4
9
0
1
2
3
4
5
6
7
1
8
2
3
0
1
2
3
1
2
3
8
0
1
2
3
5
7
4
5
4
5
4
1
2
3
4
0
1
2
3
5
4
7
5
5
8
9
6
7
4
9
6
7
7
9
6
7
Counting sort
ƒ Non si basa sul confronto ma …
Assunzione: per ogni input < a1, …, aN >, ai є[0..M]
Idea:
□ Contare per ogni elemento dell’input x il numero di
elementi minori di x.
□ Usare questa informazione per posizionare l’elemento
x direttamente nella sua posizione dell’array di output.
Esempio: Se ci sono 17 elementi minori di x, allora x sarà
posto nella posizione 17 nell’output (Ricordarsi che gli
array in C hanno come indice iniziale 0).
Counting sort
void countingsort (int v[], int dim, int ris[])
{ int i, occ[M+1];
for (i = 0; i < M+1; i++)
/* inizializza occ */
occ[i] = 0;
for (i = 0; i < dim; i++)
occ[v[i]] ++;
/* occ[i] == k sse i occorre k volte in v */
for (i = 1 ; i < M+1; i++)
occ[i] += occ[i-1]; /*occ[i] contiene il num di elementi ≤ i in v */
for (i = dim-1; i>=0; i--) {
ris[occ[v[i]] -1] = v[i];
/*dispone gli elementi di v in ris */
occ[v[i]]--;
}
}
Esempio
v
occ
occ
occ
ris
ris
5
2
3
1
5
0
3
0
1
2
3
4
5
6
1
1
1
2
0
2
0
1
2
3
4
5
1
2
3
5
5
7
0
1
2
3
4
5
1
2
3
4
5
7
0
1
2
3
4
5
?
?
?
?
3
?
?
0
1
2
3
4
5
6
0
1
2
3
3
5
5
0
1
2
3
4
5
6
occ alla fine del secondo for.
occ alla fine del terzo for.
Prima iterazione del quarto ciclo.
Array ordinato: fine
quarto ciclo.
Esercizio
ƒ Dato un array v di dimensione n con interi
nell’itervallo [0..M], utilizzare un’adeguata
struttura dati in modo da poter determinare
quanti elementi di v appartengono a un generico
intervallo [a..b], utilizzando una semplice
sottrazione.