18 Algoritmi di ordinamento C++

Transcript

18 Algoritmi di ordinamento C++
Algoritmi di ordinamento
Gli ordinamenti interni sono fatti su sequenze in memoria centrale
Gli ordinamenti esterni sono fatti su sequenze in memoria di massa
Fondamenti di Informatica
Per metodi interni è possibile l’accesso casuale ai dati, mentre per i
metodi esterni è possibile solo l’accesso sequenziale o a blocchi di
grandi dimensioni
18. Algoritmi di ordinamento in C++
Si usano i metodi esterni quando si hanno limitazioni della RAM del
calcolatore rispetto alla quantità di dati
Corso di Laurea in Ingegneria Informatica e dell’Automazione
A.A. 2012-2013
2° Semestre
Prof. Giovanni Pascoschi
Fondamenti di Informatica A.A. 2012-2013
Algoritmi di ordinamento
a cura di Pascoschi Giovanni
2
Algoritmi di ordinamento
Gli algoritmi di ordinamento interno si dividono in:
Algoritmi semplici - complessità O(n2) prossima lezione
Algoritmi evoluti - complessità O(n*log2n) prossima lezione
Algoritmi Semplici di Ordinamento. Algoritmi che presentano una
complessità proporzionale a n2, dove n è il numero di informazioni da
ordinare. Essi sono caratterizzati da poche e semplici istruzioni,
dunque presentano un codice molto ristretto.
Algoritmi Evoluti di Ordinamento. Algoritmi che offrono una
complessità computazionale proporzionale a n*log2n (che è sempre
inferiore a n2) . Tali algoritmi sono molto più complessi, fanno molto
spesso uso di ricorsione. La convenienza del loro utilizzo si ha
unicamente quando il numero n di informazioni da ordinare è molto
elevato.
Si distinguono i metodi di ordinamento diretti o indiretti
Un metodo di ordinamento si dice diretto se accede all’intero
record del dato da confrontare, indiretto se utilizza dei riferimenti
(puntatori) per accedervi
Metodi indiretti sono utili quando si devono ordinare dati di grandi
dimensioni in questo modo non è necessario spostare i dati in
memoria ma solo i puntatori ad essi.
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
3
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
4
Algoritmi semplici di ordinamento
Algoritmo per scambio
Ordinamento per scambio
Algoritmo tradizionale di ordinamento:
Ordinamento per selezione (selection sort)
1. Confronta il primo elemento con i successivi, effettuando uno
scambio di posizione quando l’ordine dei due elementi non è corretto
Ordinamento per inserimento (insertion sort)
2. Alla fine del ciclo ne parte un altro che ripete la stessa operazione a
partire dal suo adiacente (p.e. secondo elemento) e cosi’ via
Ordinamento a bolle (bubblesort)
Ordinamento shell
12
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
5
Algoritmo per scambio
24
3
10
35
Fondamenti di Informatica A.A. 2012-2013
41
2
71
a cura di Pascoschi Giovanni
6
Algoritmo per selezione (selection sort)
void scambio(int A[ ], int n) {
1. L’algoritmo selection sort seleziona l’elemento minore (maggiore) del
sottovettore e mettendolo al primo posto
int i,j;
for(i=0; i<n-1; i++) {
for(j=i+1; i<n; i++) {
if (A[i] > A[j]) {
swap(A[i], A[j]);
}
}
}
2. Si procede applicando lo stesso procedimento al sottovettore non
ordinato e cosi’ via
}
12
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
7
24
3
10
Fondamenti di Informatica A.A. 2012-2013
35
41
2
71
a cura di Pascoschi Giovanni
8
Algoritmo per selezione
Algoritmo per inserimento
L’algoritmo per inserimento consiste nell’inserire un elemento alla
volta nella posizione che gli spetta in un vettore già ordinato, partendo
dal vettore vuoto
void scambio(int A[ ], int n) {
int i, j, indicemin;
for(i=0; i<n-1; i++) {
indicemin = i;
for(j=i+1; i<n; i++) {
if (A[j] < A[indicemin]) indicemin = j;
}
swap(A[i], A[indicemin]);
}
12
10
35
41
2
71
12
24
3
12
24
3
10
12
24
3
10
12
24
35
3
10
12
24
35
41
2
3
10
12
24
35
41
2
3
10
12
24
35
41
// nuova pos. minore
a cura di Pascoschi Giovanni
9
Algoritmo per inserimento
Fondamenti di Informatica A.A. 2012-2013
71
a cura di Pascoschi Giovanni
10
Algoritmo bubblesort
L’algoritmo bubblesort consiste nel confrontare ogni elemento con il
successivo. Se gli elementi non sono ordinati si scambiano i valori, e
cosi’ via.
void scambio(int A[ ], int n) {
int i, j, value;
// obiettivo posizionare A[i]
for(i=0; i<n; i++) {
// i identifica il sottovettore serie[0]-serie[i]
value = A[i];
// A[i] temporaneamente salvato in value
j = i;
// j attraversa serie[j] cercando la pos. corretta
while( j>0 && value < A[j-1]) {
A[j] = A[j-1];
//sposta gli elementi a destra
j--;
}
A[j] = value;
}
1.Il valore piu’ piccolo (o piu’ grande) affiorerà come una bolla in un
liquido
}
Fondamenti di Informatica A.A. 2012-2013
3
12
// posizione del minore
}
Fondamenti di Informatica A.A. 2012-2013
24
a cura di Pascoschi Giovanni
11
12
24
3
10
35
41
2
71
12
3
10
24
35
2
41
71
3
10
12
24
2
35
41
71
3
10
12
2
24
35
41
71
3
10
2
12
24
35
41
71
3
2
10
12
24
35
41
71
2
3
10
12
24
35
41
71
2
3
10
12
24
35
41
71
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
12
Algoritmo bubblesort
Algoritmo shell
void bubblesort(int A[ ], int n) {
L’algoritmo shell è un ordinamento per inserimento con incrementi
decrescenti (misto tra inserimento e bubble)
int i;
bool swapped;
do {
swapped=false;
for(i=0; i<n-1; i++) {
if (A[i]>A[i+1]) {
swap(A[i], A[i+1]);
swapped=true;
}
}
} while(swapped);
La lentezza dell'ordinamento per inserzione e' dovuta al fatto che le
operazioni di scambio avvengono tra elementi adiacenti. Se l'elemento
piu' piccolo e' alla fine dell'array ci vogliono N passi per disporlo al
posto giusto
L'idea dello shell sort e' di scambiare gli elementi prima molto
distanti tra loro e poi progressivamente quelli piu' vicini
}
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
13
Algoritmo shell
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
14
Algoritmo shell (esempio)
1.Si divide il vettore di n elementi in n/2 gruppi di due elementi, con un
intervallo di n/2 e si ordina ciascun gruppo
20
12
5
31
24
35
1
14
2.Si divide il vettore in n/4 gruppi di quattro elementi con salto n/4 e si
ordinano i singoli gruppi separatamente
20
12
1
14
24
35
5
31
1
12
5
14
20
31
24
35
3.Si ripete il processo finchè non si arriva all’ultimo passo con
l’ordinamento di n gruppi ciascuno di 1 elemento (in questo passo il
metodo coincide con il metodo a bolle)
1
5
12
14
20
24
31
35
1
5
12
14
20
24
31
35
4.Se si eseguono piu' passate ordinando l'array prima con passo
“salto” grande e poi decrementandolo fino a passo 1 si ottiene un array
via via sempre piu' ordinato fino ad averlo del tutto ordinato
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
15
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
16
Algoritmo shell (esempio)
Algoritmo evoluto di ordinamento : Quicksort
void ord_shell(int A[ ], int n) {
int i, j, salto = n/2;
while( salto >0 ) {
for(i=salto; i<n; i++) {
// ordinamento parziale di i vettori:i indice vettori
j = i – salto;
// gli elementi stanno a distanza salto
while( j >= 0) {
k = j + salto;
// k e j indici degli elementi da confrontare
if( A[j] <= A[k]) j= -1; // elementi contigui j e k del vettore fine ciclo
else {
swap(A[j], A[k]);
j = j – salto;
}
}
}
salto = salto /2;
}
Si consideri un vettore di n elementi e lo si ordini con algoritmi
semplici, con un tempo di calcolo proporzionale a n2.
Si supponga, invece di dividere il vettore da ordinare in due
sottovettori di n/2 elementi ciascuno e di ordinare le due metà
separatamente.
Applicando sempre gli algoritmi non evoluti, si avrebbe un tempo di
calcolo pari a (n/2)2 + (n/2)2=n2/2.
Se riunendo i due sottovettori ordinati si potesse riottenere il vettore
originario tutto ordinato avremmo dimezzato il tempo di calcolo
Se questo ragionamento si potesse applicare anche immaginando
una decomposizione del vettore originario in quattro, si avrebbe un
tempo di calcolo totale pari a:
(n/4)2 + (n/4)2 + (n/4)2 + (n/4)2=n2/4.
Se si potesse dividere in 8, si avrebbe un tempo ancora più basso, e
così via.
}
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
17
Algoritmo Quicksort
Problema
Supponiamo di dividere il
vettore A a metà e di ordinare i
due
pezzi,
separatamente
ottenendo i due vettori A1 e A2.
Il vettore ricomposto non è però
ordinato.
Il vincolo da porre è chiaro:
possiamo applicare questo
metodo solo se il massimo
elemento in A1 è inferiore o
uguale al minimo elemento di
A2.
L’operazione che crea due
parti
con
la
suddetta
caratteristica
si
dice
partizionamento del vettore.
Fondamenti di Informatica A.A. 2012-2013
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
18
Algoritmo Quicksort
18
12 1
55 22
17 25
19 39
44
0
1
3
5
7
9
2
4
6
8
1.
2.
Vett A
1
12
0 1
18
22
55
17 19 25 39 44
2
3
4
0
Vett A1
1
2
3
3.
4.
4
Vett A2
1 12 18 22 55 17 19 25 39 44
0 1
2
3
4
5
6
7
8
5.
9
6.
7.
Utilizzo di un pivot centrale
a cura di Pascoschi Giovanni
19
il vettore da ordinare viene delimitato dall'indice del primo elemento
(inf) e dall'indice dell'ultimo elemento (sup).
viene scelto un elemento del vettore di indice compreso tra inf e sup,
chiamato pivot, scelto del tutto casualmente.
Potrebbe essere
l'elemento di indice (inf+sup)/2.
vengono utilizzati due indici i, j che vengono inizializzati a i=inf e j=sup.
l'indice i viene incrementato di 1 fino a quando l'elemento di indice i
non è maggiore o uguale al pivot.
l'indice j viene decrementato di 1 fino a quando l'elemento di indice j
non è minore o uguale al pivot.
nel caso in cui i < j, gli elementi di indici i e j vengono scambiati, e poi i
viene incrementato e j decrementato (in modo unitario)
nel caso in cui i = j, non si effettua lo scambio, ma i viene incrementato
di 1 e j viene decrementato di 1
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
20
Algoritmo Quicksort
Algoritmo Quicksort
8.
se i >j (i due indici si sono “incrociati”) allora la fase di
partizionamento termina. In questo modo risulta che:
tutti gli elementi di indice appartenente a inf,..,j sono minori o
uguali del pivot
tutti gli elementi di indice appartenente a i,..,sup sono
maggiori o uguali del pivot
tutti gli elementi di indice appartenente a j+1,..,i-1 sono uguali
al pivot
9. l'algortimo QuickSort viene applicato ricorsivamente al sottovettore
individuato dagli indici (inf,j), se tale sottovettore contiene almeno un
elemento, ossia se inf < j
10. l'algortimo QuickSort viene applicato ricorsivamente al sottovettore
individuato dagli indici (i,sup), se tale sottovettore contiene almeno
un elemento, ossia se i < sup
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
12
Fondamenti di Informatica A.A. 2012-2013
3
51
41
2
71
j=sup
2
24
3
10
51
41
12
71
2
10
3
24
51
41
12
71
quick
21
10
pivot
i=inf
Algoritmo Quicksort
void QSort (int A[ ], int inf, int sup)
{
int pivot;
int i,j;
pivot = A[(inf+sup)/2];
i=inf; j=sup;
do {
while (A[ i ] < pivot) i++;
while (A[ j ] > pivot) j- -;
if (i<j) swap(A[i], A[j]);
if (i<=j) {
i++;
j--;
}
} while (i<=j);
if (inf<j) QSort(A,inf,j);
if (i<sup) QSort(A,i,sup);
}
24
Fondamenti di Informatica A.A. 2012-2013
quick
a cura di Pascoschi Giovanni
22
Algoritmo Quicksort
Caso migliore: il caso in cui il vettore originario è decomposto
nella prima passata in due sottovettori di dimensione uguale. Il
pivot viene scelto pari esattamente al valore mediano degli
elementi contenuti nel vettore
// ciclo per effettuare il partizionamento
// trova A[i] >= pivot
// trova A[j] <= pivot
Caso peggiore: il vettore originario è decomposto in due
sottovettori, di cui il primo ha dimensione uguale alla dimensione
originaria meno 1, e l’altro ha una dimensione unitaria. Il pivot
coincide con l’elemento massimo del vettore.
// si ripete finche’ il partizionamento termina
a cura di Pascoschi Giovanni
23
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
24
Riepilogo della lezione
Fine della lezione
Algoritmi di ordinamento in C++
Ordinamento per scambio
Ordinamento per selezione (selection sort)
Ordinamento per inserimento (insertion sort)
Ordinamento a bolle (bubblesort)
Ordinamento shell
Ordinamento Quicksort
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
Domande?
25
Fondamenti di Informatica A.A. 2012-2013
a cura di Pascoschi Giovanni
26