31
A. Ferrari Algoritmi notevoli in linguaggio C

in linguaggio C - ..::Alberto Ferrari::.. · in linguaggio C . algoritmi A. Ferrari ... di nome v con n elementi con funzioni che restituiscono l ... Selection Sort in C (2) A. Ferrari

Embed Size (px)

Citation preview

A. Ferrari

Algoritmi notevoli

in linguaggio C

A. Ferrari algoritmi

o ricerca

(verificare la presenza di un valore in un array)

o ricerca sequenziale (array non ordinato)

o ricerca sequenziale (array ordinato)

o ricerca binaria (array ordinato)

o ordinamento

(ordinare i valori all’interno di un array in modo crescente o decrescente)

o stupid Sort

o selection Sort

o subble Sort

o merge

(fondere due array ordinati in un terzo array)

A. Ferrari algoritmi di ricerca

o in generale un algoritmo di ricerca si pone come obiettivo quello

di trovare un elemento avente determinate caratteristiche

all'interno di un insieme di elementi

o nel nostro caso definiremo algoritmi che verificano la presenza di

un valore in un array

o l’array può essere non ordinato o ordinato (ipotizziamo

l’ordinamento crescente)

A. Ferrari ricerca sequenziale

o la ricerca sequenziale (o completa) consiste nella scansione

sequenziale degli elementi dal primo all’ultimo e si interrompe

quando il valore cercato è stato trovato, oppure quando si è sicuri

che il valore non può essere presente

o ha il vantaggio di poter essere applicata anche a dati non

ordinati

o negli esempi tratteremo la ricerca del valore x in un array double

di nome v con n elementi con funzioni che restituiscono l’indice

dell’elemento dell’array con valore x o -1 in caso di valore non

trovato

A. Ferrari ricerca sequenziale in C

int ricercaSequenziale(double v[], int n, double x)

{

int i=0;

while (i<n && x!=v[i])

i++;

if (i>=n)

return -1;

return i;

}

A. Ferrari ricerca sequenziale in array ordinato

int ricercaSequenziale(double v[], int n, double x)

{

int i=0;

while (i<n && v[i]<x)

i++;

if (i<n && v[i]==x)

return i;

return -1;

}

A. Ferrari ricerca binaria o logaritmica

o l'algoritmo è simile al metodo usato per trovare una parola sul dizionario: sapendo che il vocabolario è ordinato alfabeticamente, l'idea è quella di iniziare la ricerca non dal primo elemento, ma da quello centrale, cioè a metà del dizionario

o il valore ricercato viene confrontato con il valore dell'elemento preso in esame: o se corrisponde, la ricerca termina indicando che l'elemento è

stato trovato

o se è inferiore, la ricerca viene ripetuta sugli elementi precedenti (sulla prima metà del dizionario), scartando quelli successivi

o se invece è superiore, la ricerca viene ripetuta sugli elementi successivi (sulla seconda metà del dizionario), scartando quelli precedenti

o se tutti gli elementi sono stati scartati, la ricerca termina indicando che il valore non è stato trovato

A. Ferrari ricerca binaria in C

int ricercaBinaria(double v[], int n, double x)

{

int primo,ultimo,medio;

primo = 0;

ultimo = n-1;

while(primo<=ultimo) // non tutti gli elementi sono stati scartati

{

medio = (primo+ultimo)/2;

if(v[medio]==x)

return medio; // valore x trovato alla posizione medio

if(v[medio]<x)

primo = medio+1; // scarto la prima metà

else

ultimo = medio-1; // scarto la seconda metà

}

// se il programma arriva qui l’elemento non e’ stato trovato

// e sono stati scartati tutti gli elementi

return -1;

}

A. Ferrari ricerca binaria ricorsiva

o l’algoritmo si presta ad una definizione ricorsiva

o ad ogni chiamata della funzione si verifica se l’elemento ricercato

si trova al centro dell’intervallo e in tal caso la funzione termina

con successo, in caso contrario si modifica l’intervallo di ricerca e

si effettua una nuova chiamata della funzione

o nel caso in cui l’intervallo di ricerca sia nullo si termina la

ricorsione con insuccesso

A. Ferrari implementazione ricorsiva

int ricercaRicorsiva(double v[], int inizio, int fine, double x)

{

if(inizio>fine) // terminazione con insuccesso

return -1;

int medio=(inizio+fine)/2;

if (v[medio]==x) // terminazione con successo

return medio;

if (v[medio]>x)

return ricercaRicorsiva(v,inizio,medio-1,x);

else

return ricercaRicorsiva(v,medio+1,fine,x);

}

A. Ferrari confronto fra gli algoritmi

o in genere l’efficienza si misura in base al numero di

confronti effettuati che dipende da n (lunghezza

dell’array)

o si individuano il caso migliore e peggiore ma in

generale interessa il caso medio

A. Ferrari

Algoritmi di ordinamento

A. Ferrari alcuni algoritmi

o Stupid Sort o particolarmente inefficiente, come si può intuire dal nome

consiste nel mischiare in qualche modo gli elementi dell’array poi controllare se è ordinato e, se non lo è, ricominciare da capo

o Selection Sort o consiste in più scansioni dell’array: al termine della prima il

primo elemento conterrà il valore minore, poi si proseguirà ordinando la parte successiva dell’array

o Bubble Sort o consiste nella scansione dell’array elemento per elemento,

scambiando i valori dei due elementi consecutivi, quando il primo è maggiore del secondo

A. Ferrari scambio di elementi

o tutti gli algoritmi di ordinamento si basano sullo scambio degli

elementi dell’array.

o in tutti gli esempi faremo riferimento nelle funzioni a un generico

array di double v di lunghezza n.

o per lo scambio del valore di due elementi useremo la funzione:

void scambia(double *e1,double *e2)

{

double app; // appoggio

app = *e1;

*e1 = *e2;

*e2 = app;

}

A. Ferrari Stupid sort

o l’algoritmo è probabilistico

o la ragione per cui l'algoritmo arriva quasi sicuramente a una

conclusione è spiegato dal teorema della scimmia instancabile: ad

ogni tentativo c'è una probabilità di ottenere l'ordinamento

giusto, quindi dato un numero illimitato di tentativi, infine

dovrebbe avere successo

o il Bozo Sort è una variante ancora meno efficiente. Consiste nel

controllare se l'array è ordinato e, se non lo è, prendere due

elementi casualmente e scambiarli (indipendentemente dal fatto

che lo scambio aiuti l'ordinamento o meno)

A. Ferrari Bozo Sort in C

void bozoSort(double v[], int n){

while(ordinato(v,n)!=1)

mescola(v,n);

}

int ordinato(double v[],int n){

int i; // indice array

for(i=0;i<n-1;i++)

if(v[i]>v[i+1])

return 0; //non ordinato

return 1; //ordinato

}

void mescola(double v[], int n){

int i1,i2 // indici casuali

i1=(rand() % n);

i2=(rand() % n);

scambia(&v[i1], &v[i2]);

}

A. Ferrari Selection Sort

o l’algoritmo ricerca l’elemento minore della regione del vettore da

ordinare e lo sposta all’inizio della regione stessa

o ad ogni scansione viene spostato un elemento del vettore nella

posizione corretta

o l’ordinamento ha termine quando la regione considerata è

costituita da un solo elemento

A. Ferrari

1 23 4 -56 65 21 32 15 0 -3

-56 23 4 1 65 21 32 15 0 -3

-56 -3 4 1 65 21 32 15 0 23

-56 -3 0 1 65 21 32 15 4 23

-56 -3 0 1 65 21 32 15 4 23

-56 -3 0 1 4 21 32 15 65 23

-56 -3 0 1 4 15 32 21 65 23

-56 -3 0 1 4 15 21 32 65 23

-56 -3 0 1 4 15 21 23 65 32

-56 -3 0 1 4 15 21 23 32 65

Array di partenza

Scansione 1

Scansione 2

Scansione 3

Scansione 4

Scansione 5

Scansione 6

Scansione 7

Scansione 8

Scansione 9

un esempio

A. Ferrari Selection Sort in C (1)

void selectionSort(double v[],int n) {

int s; //scansioni

int i; //indice array

for (s = 0; s < n - 1; s++)

{

// n-1 scansioni (n è la dimensione dell’array)

for (i = s + 1; i < n; i++)

{

// scambio di posizione fra il primo elemento

// della sequenza e un elemento con valore minore

if (v[i] < v[s])

{

scambia(&v[i],&v[s]);

}

} // fine ciclo interno

}

}

A. Ferrari Selection Sort in C (2)

void selectionSort(double v[],int n) {

int s; //scansioni

int i; //indice array

for (s = 0; s < n - 1; s++)

{

// n-1 scansioni (n è la dimensione dell’array)

// la posizione dell’elemento minore è inizialmente

// la prima della regione da analizzare

int posizMin = s;

for (i = s + 1; i < n; i++)

{

// ricerca la posizione dell’elemento minore

// fra quelli presenti nella regione

if (v[i] < v[posizMin])

posizMin = i;

}

scambia(&v[s],&v[posizMin]);

}

}

A. Ferrari Bubble Sort

o consiste nella scansione dell’array elemento per elemento,

scambiando i valori dei due elementi consecutivi, quando il primo

è maggiore del secondo

o al termine della scansione, in genere l’array non risulta ordinato

e si deve procedere a una nuova scansione e alla conseguente

serie di eventuali scambi tra i valori di due elementi consecutivi

o sicuramente l’array risulta ordinato quando si sono effettuate n – 1 scansioni, se n sono gli elementi dell’array

o è detto bubblesort (ordinamento a bolle) per analogia con le bolle

d’aria nell’acqua che, essendo leggere, tendono a spostarsi verso

l’alto

A. Ferrari un esempio

A. Ferrari Bubble Sort in C (1)

void bubbleSort(double v[], int n){

int s,i;

for(s=0;s<n-1;s++)

for(i=0;i<n-1;i++)

if (v[i]>v[i+1])

scambia(&v[i],&v[i+1];

}

A. Ferrari Bubble Sort in C (2)

• E’ possibile migliorare l’efficienza dell’algoritmo controllando se sono stati effettuati spostamenti, in caso negativo l’array risulta già ordinato

void bubbleSort(double v[], int n){

int spostamento;

int s=0;

int i;

do

{

spostamento = 0; //nessuno spostamento

for(i=0;i<n-1;i++)

if (v[i]>v[i+1])

{

spostamento = 1; //effettuato uno spostamento

scambia(&v[i],&v[i+1]);

}

s++;

} while (spostamento==1 && s<n-1);

}

A. Ferrari

Merge

fusione di due array ordinati

A. Ferrari algoritmo

o si parte da due array ordinati a e b per ottenere un

terzo array c ordinato e contenente sia i dati presenti

in a che quelli presenti in b

o l’algoritmo prevede la scansione dei due array con due

indici diversi trasferendo in c l’elemento con valore

minore

A. Ferrari passaggio 1

A. Ferrari passaggio 2

A. Ferrari passaggio 3

A. Ferrari

void merge(float a[], int na, float b[], int nb, float c[]){

int i=0,j=0,k=0;

while (i<na && j<nb) { // né a né b sono «finiti»

if (a[i]<b[j]) {

c[k]=a[i]; // prendo elemento di a

i++;

}

else {

c[k]=b[j]; // prendo elemento di b

j++;

}

k++;

} // … segue …

A. Ferrari … segue

while (i<na) { // è finito b allora copio il resto di a

c[k]=a[i];

k++;

i++;

}

while (j<nb) { // è finito a allora copio il resto di b

c[k]=b[j];

k++;

j++;

}

} // fine funzione