booble bubble

Transcript

booble bubble
2
Algoritmi di ordinamento

Algoritmi

Ver. 2.4
Lo scopo è ordinare in senso [de]crescente il
contenuto di un vettore di N elementi senza
utilizzare un secondo vettore
Esiste molta letteratura scientifica a riguardo
e molti metodi adatti a vari casi, ma qui si
considerano tre semplici algoritmi di esempio
molto per l’ordinamento in senso crescente (o
meglio, non-decrescente):



Selection sort
Bubble sort
Insertion sort
© 2010 - Claudio Fornaro - Corso di programmazione in C
3
Selection sort semplificato - I

Si confronta il primo elemento del vettore con
tutti gli altri, man mano che si trova un valore
minore del primo, lo si scambia con il primo.
Dopo questa operazione il valore minimo è
nella prima posizione
è il successivo a 0
(pos. 0) del vettore
for (j= 1; j<N; j++)
if (v[j] < v[0])
5 7 5 4 2 6
{
tmp = v[j];
v[j] = v[0];
4 7 5 5 2 6
v[0] = tmp;
}
2 7 5 5 4 6
4
Selection sort semplificato - II

Se si ripete lo stesso identico procedimento
per tutti gli elementi a partire dal secondo, si
determina il secondo valore più piccolo e lo si
colloca al secondo posto
è il successivo a 1
for (j= 2; j<N; j++)
if (v[j] < v[1])
2 7 5 5 4 6
{
tmp = v[j];
v[j] = v[1];
2 5 7 5 4 6
v[1] = tmp;
}
2 4 7 5 5 6
5
Selection sort semplificato - III

Se si ripete lo stesso identico procedimento
per tutti gli elementi a partire dall’i-esimo, si
determina l’i-esimo valore più piccolo e lo si
colloca all’i-esimo posto
6
Selection sort semplificato -IV

è il successivo a i
Se si ripete questo procedimento per tutti i
valori di i da 0 fino al penultimo (l’ultimo va a
posto da sé) si ottiene l’ordinamento in senso
crescente di tutto il vettore
for (i=0; i<N-1; i++)
for (j=i+1; j<N; j++)
if (v[j] < v[i])
{
tmp = v[j];
v[j] = v[i];
v[i] = tmp;
}
for (j=i+1; j<N; j++)
if (v[j] < v[i])
{
tmp = v[j];
v[j] = v[i];
v[i] = tmp;
}
7
Selection sort - I

8
Selection sort - II
Il primo passo è quello di individuare il
minimo tra gli elementi del vettore e
scambiarlo con quello nella prima posizione,
il primo valore è ora al posto giusto
è il successivo a 0
jmin = 0;
for (j= 1; j<N; j++)
if (v[j] < v[jmin])
jmin = j;
5 7 5 1 4 3
tmp = v[jmin];
v[jmin] = v[0];
v[0] = tmp;
1 7 5 5 4 3

Se si ripete lo stesso identico procedimento
per tutti gli elementi a partire dal secondo, si
determina il secondo valore più piccolo e lo si
colloca al secondo posto
è il successivo a 1
jmin = 1;
for (j= 2; j<N; j++)
if (v[j] < v[jmin])
jmin = j;
1 7 5 5 4 3
tmp = v[jmin];
v[jmin] = v[1];
v[1] = tmp;
1 3 5 5 4 7
9
Selection sort - III

10
Selection sort - IV
Se si ripete lo stesso identico procedimento
per tutti gli elementi a partire dall’i-esimo, si
determina l’i-esimo valore più piccolo e lo si
colloca all’i-esimo posto
è il successivo a i
jmin = i;
for (j=i+1; j<N; j++)
if (v[j] < v[jmin])
jmin = j;
tmp = v[jmin];
v[jmin] = v[i];
v[i] = tmp;

Se si ripete questo procedimento per tutti i
valori di i da 0 fino al penultimo (l’ultimo va a
posto da sé) si ottiene l’ordinamento in senso
crescente di tutto il vettore
for (i=0; i<N-1; i++)
{ jmin = i;
for (j=i+1; j<N; j++)
if (v[j] < v[jmin])
jmin = j;
tmp = v[jmin];
v[jmin] = v[i];
v[i] = tmp;
}
11
Bubble sort - I

12
Bubble sort - II
Se si scorrono tutti gli elementi di un vettore
e ogni volta che si trovano due valori
ADIACENTI non in ordine (il più piccolo dei 2
a destra del più grande) li si scambia: il più
grande di tutti risale a destra
3 1 5 7 4 3
for (j=0; j<N-1; j++)
if (v[j] > v[j+1])
1 3 5 7 4 3
{
tmp = v[j];
1 3 5 4 7 3
v[j] = v[j+1];
v[j+1] = tmp;
}
1 3 5 4 3 7

Ripetendo N-1 volte questa operazione, tutti i
valori risalgono verso destra fino ad occupare
la posizione corretta e quindi vengono
ordinati in senso crescente
for (i=0 ; i<N-1; i++)
for (j=0; j<N-1; j++)
if (v[j] > v[j+1])
{
tmp = v[j];
v[j] = v[j+1];
v[j+1] = tmp;
}
13
Bubble sort - III

14
Bubble sort - IV
Inefficienza: gli ultimi valori vengono in ogni
caso confrontati, anche quando sono già stati
collocati; per evitare perdita di tempo in
questi controlli inutili si ferma prima della fine
il ciclo interno, sfruttando il ciclo esterno
for (i=N-1; i>0 ; i--)
for (j=0; j<i ; j++)
if (v[j] > v[j+1])
{
tmp = v[j];
v[j] = v[j+1];
v[j+1] = tmp;
}

Inefficienza: se pochi valori sono fuori posto e
l’ordinamento si ottiene prima delle N-1
passate, i cicli continuano ad essere eseguiti.
Lo si fa terminare se non ci sono stati scambi
scambi = SI;
for (i=N-1; i>0 && scambi ;i--)
{ scambi = NO;
for (j=0; j<i ; j++)
continua solo
if (v[j] > v[j+1])
se ci sono
{ scambi = SI;
stati
scambi
tmp = v[j];
v[j] = v[j+1];
v[j+1] = tmp; }
}
15
Insertion sort - I

Insertion sort - II
Per ciascuno degli elementi a partire dal 2o
(l’elemento da sistemare si chiama chiave):
si copia il valore della chiave in una variabile (key)
si scalano a destra di una posizione tutti gli
elementi precedenti alla chiave finché non ne
viene trovato uno con valore inferiore a key
4.
al posto di quest’ultimo viene messo key
Notare che gli elementi a sinistra della chiave sono
sempre già ordinati in senso crescente grazie alle
passate precedenti
3 2
1.
2-3.
1 5 7 3 4 8
key
4
3
1
16
1 3 5 7 4 8
ordinati

for (j=1; j<N; j++)
{
key = v[j];
for (i=j-1; i>=0 && v[i]>key; i--)
v[i+1] = v[i];
v[i+1] = key;
}
17
Esercizi
1.
2.
3.
18
Algoritmi di ricerca
Per ciascuno degli algoritmi di ordinamento
precedentemente descritti (variazioni incluse),
si scriva un programma completo che ordini in
senso crescente (o meglio, non-decrescente)
un vettore di N numeri interi.
Si misurino i tempi di esecuzione usando la
funzione clock() in <time.h>


Si vuole cercare un dato valore val in un
vettore vett di N elementi
Si possono considerare i due casi:


vettore non ordinato
vettore ordinato
Per ciascuno degli algoritmi di ordinamento
precedentemente descritti (variazioni incluse),
si scriva un programma completo che ordini in
senso decrescente (o meglio, noncrescente) un vettore di N numeri interi.
19
20
Ricerca in vettore non ordinato
Ricerca in vettore non ordinato


Si deve scorrere tutto il vettore in quanto val
può essere in qualsiasi posizione
for (i=0; i<N && vett[i]!=val; i++)
;
if (i == N)
printf("Non trovato\n");
else
printf("Trovato\n");

Il ciclo termina in 2 casi:



Deve stabilire per quale motivo il ciclo è finito



Finché non lo trova, continua a cercare

è stato trovato il valore
ha finito di cercare (invano) in tutti gli elementi
se trova: i < N
se non lo trova: i = N
Non si deve controllare se val è stato trovato
verificando la condizione vett[i]=val
perché se non lo trova i vale N e vett[N]
identifica un elemento inesistente
Al massimo (nel caso peggiore) fa N controlli
Ricerca in vettore ordinato
21
Ricerca lineare








left=0; right=N-1;
while (right>=left)
{ m=(left+right)/2;
if (val==vett[m])
break;
if (val<vett[m])
right=m-1;  elimina la metà destra
else
left=m+1;  elimina la metà sinistra
}
if (val==vett[m])
printf("Trovato\n");
else
printf("Non trovato\n");
23
Dicotomica (o binaria)

22
Ricerca dicotomica (o binaria)
Non serve scorrere tutto il vettore, ci si ferma
non appena si supera il valore cercato
for (i=0; i<N && vett[i]<val; i++)
;
if (i<N && val == vett[i])
printf("Trovato\n");
else
printf("Non trovato\n");
Quando vett[i] >= val il ciclo viene
interrotto e si controlla se val è stato trovato
Al massimo fa N controlli
Ricerca in vettore ordinato

Ricerca in vettore ordinato
Inizializza due indici left e right al primo e
all’ultimo indice del vettore (0 e N-1)
Calcola l’indice del valore centrale: m
Se vett[m] è il valore cercato, termina
Altrimenti se val è minore del valore centrale,
arretra l’indice destro right al centro m (così
dimezza il numero di valori in cui cercare)
Altrimenti se val è maggiore del valore
centrale, avanza l’indice sinistro left al centro
Ripetendo questa operazione, si dimezza ogni
volta il vettore
Veloce: al massimo fa log2(N+1) controlli
24
Programmazione a stati


Per stato si intende la situazione del
programma in un dato istante (es. “sta
leggendo i caratteri di una parola”)
Mentre il programma viene eseguito esso
cambia di stato in seguito al verificarsi di
eventi (es. lettura di un carattere da
analizzare), la transizione può portare allo
stesso stato di partenza (anello)
25
Programmazione a stati

Programmazione a stati
Graficamente:





gli stati sono disegnati come cerchi o ovali
le transizioni sono disegnate come archi orientati
nei punti di partenza degli archi si indicano gli
eventi che causano le transizioni di stato
se appropriato (c’è spazio, non sono troppe
informazioni) sugli archi si indicano anche le azioni
da intraprendere nelle transizioni
azione
evento
azione
Stato1
evento
26


evento
Stato2
azione
Nel codice l’informazione sullo stato viene
mantenuta tramite una variabile di stato, in
genere di tipo enum o int
Tipicamente i valori che la variabile di stato
può assumere sono definiti da enum o con
#define
Se i valori sono costanti e dagli stati partono
diverse possibili transizioni, lo switch è
spesso il costrutto di elezione
evento
azione
27
Programmazione a stati

Esempio (es. 4 sui file)
Si scriva un programma che chieda il nome di
un file contenente un testo qualsiasi e di
questo conti quante sono le parole che
iniziano con ciascuna lettera dell’alfabeto.
Esempio di output:
Parole che iniziano con A: 45
Parole che iniziano con B: 12
Parole che iniziano con C: 27
…
Parole che iniziano con Z: 3
28
Programmazione a stati

La variabile di stato indicherà se si stanno
leggendo i caratteri di una parola (si è “dentro”
una parola) o no (si è “fuori” da una parola) e
quindi assumerà 2 possibili valori:



DENTRO – FUORI
L’evento che può causare il cambiamento di
stato è la lettura del carattere successivo
In questo esempio ci sono solo 4 casi:




stato
stato
stato
stato
FUORI e si legge un carattere alfabetico
DENTRO e si legge un carattere alfabetico
DENTRO e si legge un carattere non-alfabetico
FUORI e si legge un carattere non-alfabetico
29
Programmazione a stati

Programmazione a stati
Più in dettaglio, se:

1.
stato FUORI e si legge un carattere alfabetico:
entra DENTRO e incrementa il contatore di quel car.
2.
stato DENTRO e si legge un carattere alfabetico:
resta DENTRO e non fa nulla
stato DENTRO e si legge un carattere non-alfab.:
va FUORI dalla parola e non fa nulla
3.
4.
30
Rappresentazione grafica corrispondente
all’esempio (no-op=no operation):
no-op
1.lettera
stato FUORI e si legge un carattere non-alfabetico:
resta FUORI e non fa nulla
incrementa
contatore lettera
FUORI
4.non-lettera no-op
2.lettera
DENTRO
3.non-lettera
no-op
31
Esercizi
3.
Homework 6
(Es. 4 sui file) Si scriva un programma che
chieda il nome di un file contenente un testo
qualsiasi e di questo conti quante sono le
parole che iniziano con ciascuna lettera
dell’alfabeto.
Lo si risolva con una soluzione a stati.
Esempio
Parole
Parole
Parole
…
Parole
32
di output:
che iniziano con A: 45
che iniziano con B: 12
che iniziano con C: 27
che iniziano con Z: 3
Si scriva un programma che per ciascuno degli
algoritmi di ordinamento visti (bubble semplice e
con variazioni, selection semplificato, selection,
insertion) per M volte (es. 100) riempia un
vettore di N valori interi casuali (es. 1000) e lo
riordini. Il programma deve misurare i tempo
impiegato per gli M ordinamenti per ciascuno
degli algoritmi. Impostare M e N in modo da
eseguire un numero significativo di prove con
vettori di dimensioni grandi (1000-10000), medi
(100-1000) e piccoli (100). Trarne le conclusioni.
33
Homework 6
Continuazione:
Includendo <time.h> si possono usare le
seguenti funzioni:
time(NULL)
restituisce un numero intero di tipo time_t che
corrisponde all’istante attuale
 difftime(time_t t2, time_t t1) restituisce
(come valore double) il numero di secondi
intercorsi tra t1 e t2
Nota: il tipo time_t è in genere un sinonimo di long
e si possono definire variabili di tale tipo:
time_t ora, t1, t2;
t1=time(NULL);
