Anteprima
Vedrai una selezione di 5 pagine su 18
Appunti Fondamenti I (C) Pag. 1 Appunti Fondamenti I (C) Pag. 2
Anteprima di 5 pagg. su 18.
Scarica il documento per vederlo tutto.
Appunti Fondamenti I (C) Pag. 6
Anteprima di 5 pagg. su 18.
Scarica il documento per vederlo tutto.
Appunti Fondamenti I (C) Pag. 11
Anteprima di 5 pagg. su 18.
Scarica il documento per vederlo tutto.
Appunti Fondamenti I (C) Pag. 16
1 su 18
D/illustrazione/soddisfatti o rimborsati
Disdici quando
vuoi
Acquista con carta
o PayPal
Scarica i documenti
tutte le volte che vuoi
Estratto del documento

N

multi-insieme V di N elementi in D (V D ) e un valore target D, il

⊆ ∈

problema della ricerca consiste nel decidere se esiste un elemento V V

i

v==V

tale che . Considereremo solo il caso in cui i dati sono memorizzati

i

in memoria primaria, ovvero il caso in cui il costo per il riferimento alle

variabili è trascurabile rispetto a quello per il confronto e la manipolazione

dei loro valori.

Implementazione per gli algoritmi di ricerca:

#include <math.h>

#define PRECISION .000000119

#define TRUE 1

#define FALSE 0

typedef unsigned short int Boolean

struct data {

float key;

…..

};

2.4.1 – Ricerca sequenziale

Se non esistono ipotesi sui valori di V, l’unica possibilità è quella di

controllarli uno ad uno, fino ad averli esauriti o fino ad aver trovato il

target, quest’ultimo caso potrebbe portare l’algoritmo ad un risultato

sbagliato in quanto potrebbero esserci più valori uguali al target. La

complessità della ricerca sequenziale è Θ(N).

Si osservi che per via della precisione finita, il test di uguaglianza è

sostituito con la verifica che la distanza relativa sia minore della

precisione di macchina, per quanto riguarda il valore della costante

PRECISION, questo può dipendere dalla particolare applicazione, un

possibile valore fornito dal file <float.h>, dove la costante di precisone di

macchina è definita dalla costante FLT_EPSILON=0.00000011920928960

-7

(circa 10 ), che è il valore corrispondente alla differenza tra il valore 1 ed

il più piccolo numero float maggiore di 1.

Boolean sequential_search(struct data * V, int N, struct data target)

{ Boolean found;

int count;

found=FALSE;

count=0;

while(found==FALSE && count<N)

{ if(is_equal(V[count].key,target.key)==TRUE)

found=TRUE;

else count++;

}

return found;

}

2.4.2 – Ricerca binaria

Se i valori di V sono ordinati, allora l’esito di un solo test può escludere

più di un elemento di V dallo spazio della ricerca. Se oltre l’ipotesi di

ordinamento possiamo anche assumere che i valori sono memorizzati su

un vettore, diventa conveniente applicare una ricerca binaria. Qui il target

viene comparato contro l’elemento in posizione mediana (V[N/2]); se è

uguale la ricerca termina con successo, se è maggiore la ricerca prosegue

nella metà destra del vettore, se è minore prosegue nella metà sinistra.

Quando la ricerca viene applicata su un vettore di lunghezza 0 è possibile

concludere che il target non è presente nell’insieme. Il caso pessimo si

realizza quando il test di uguaglianza fallisce, in tal caso il costo di

c

esecuzione è pari a un valore costante più il costo per proseguire la

ricerca sulla metà selezionata: C = Θ(ln (N))

bin 2

L’algoritmo ha una naturale implementazione in forma ricorsiva.

Boolean b_search(int * V, int N, int target)

{ if(N>0)

{ if(V[N/2]==target

return TRUE

else if(V[N/2]>target)

return b_search(V,N/2,target);

else return b_search(&V[(N/2)+1], N-(N/2)-1,target);

}

else return FALSE;

}

Si osservi che N/2 è il numero di elementi che precedono l’elemento

V[N/2], che N-(N/2)-1 è il numero di elementi che lo seguono, e che

&V[(N/2)+1] è l’indirizzo del primo elemento successivo a V[N/2]. (Vale

anche per N dispari)

Esistono inoltre forme iterative e sequenziali per la ricerca binaria (vedere

codici sul libro)

2.4.3 – Ricerca a salti (NO)

-2.5Algoritmi di ordinamento

Come già per il problema della ricerca, ci interessa considerare il caso in

cui i dati sono in memoria primaria, ovvero il caso in cui il costo per il

riferimento alle variabili è trascurabile rispetto a quello per il confronto e

la manipolazione dei loro valori.

2.5.1 – Sequential-sort

L’algoritmo sequential sort riduce il problema dell’ordinamento alla

sezione del massimo e allo swap: sull’insieme V viene selezionato il

massimo, e l’elemento che lo realizza viene swappato con l’elemento in

ultima posizione; dopodiché il problema prosegue allo stesso modo sui

primi N-1 elementi, di conseguenza dopo N-1 passaggi, il vettore è

C(SeqS)= 2

ordinato. Il costo del sequential sort è Θ(N )

Nel caso in cui l’insieme V sia rappresentato su un vettore, piuttosto che

modificare la posizione degli elementi nel vettore, si costruisce un vettore

di permutazione che fornisce la sequenza con cui il vettore può essere

visitato in ordine. Questo ha il vantaggio di non perdere l’eventuale

informazione codificata nel disordine iniziale e permette una sostanziale

ottimizzazione nel caso in cui i dati siano complessi.

void sequential_sort(int * V, int N, int * Perm)

{ int count;

int count_of_max;

int iter;

for(count=0; count<N; count++)

Perm[count]=count;

for(iter=0; iter<N; iter++)

{ for(count=1, count_of_max=0; count<N-iter; count++)

if(V[Perm[count]]>V[Perm[count_of_max]])

count_of_max=count;

swap(Perm, count_of_max, N-iter-1);

}

}

Si osservi che l’espressione V[Perm[count]]>V[Perm[count_of_max]] non

è legale se V è un tipo strutturato, in tal caso, verrebbe sostituita con

l’espressione V[Perm[count]].key>V[Perm[count_of_max]].key

Un modo per ridurre il numero di confronti dell’algoritmo è quello di

sostituire la ricerca e lo swap del massimo con la ricerca e lo swap

contemporaneo di massimo e minimo. Cosi facendo il numero di

interazione si dimezza mentre il costo di ciascuna interazione aumenta. Il

guadagno deriva dal fatto che la ricerca contemporanea di massimo e

minimo può essere effettuata con un numero di confronti minore del

doppio dei confronti richiesti per la ricerca del solo massimo: dovendo

x y max min, x y

comparare e contro e si compara inizialmente contro e

successivene il maggiore tra i due può diventare il massimo e il minore il

minimo, così facendo il numero di confronti si riduce da 4 a 3.

if(x>y)

{ if(x>max)

max=x;

if(y<min)

min=y;

}

else

{ if(y>max)

max=y;

if(x<min)

min=x;

}

2.5.2 – Bubble-sort

L’algoritmo di BubbleSort opera in iterazioni successive: nella k-esima

iterazione un indice count scandisce le posizioni da 0 a N-k-1,

confrontando ad ogni passo il valore di V[count] contro quello di

V[count+1] e permutando le posizioni dei due elementi se essi non sono

in ordine. L’algoritmo termina quando nel corso di una iterazione non

sono stati identificati due elementi fuori ordine. L’algoritmo non è

particolarmente efficiente, ma ci interessa per esemplificare il problema

della correttezza. Quest’ultimo è scomposto in due parti:

La correttezza parziale, è quella per cui se l’algoritmo termina, allora il

 risultato prodotto è corretto

La correttezza totale, si raggiunge quando alla correttezza parziale

 viene aggiunta la garanzia di terminazione

Nel caso del bubble sort, la correttezza parziale è garantita in modo

immediato: l’algoritmo termina quando nel corso di una iterazione non

sono identificati due elementi contigui fuori ordine, il che garantisce che il

vettore sia in ordine. Per quando riguarda la correttezza totale si pone il

problema di capire come aggiungere la garanzia di terminazione; questa

può essere dimostrata sulla base di due proprietà:

1. Un elemento che all’inizio dell’iterazione non è preceduto da alcun

maggiorante avanza fino ad incontrare il primo maggiorante, nel caso

particolare in cui non ha nessun maggiorante avanza fino all’ultima

posizione del vettore.

2. Un elemento che all’inizio dell’iterazione è preceduto da almeno un

maggiorante, al termine dell’iterazione è arretrato di una posizione

Al termine della k-esima iterazione, le ultime k posizioni del vettore

contengono i k maggiori elementi nel loro corretto ordine, questo implica

che entro N-1 iterazioni, gli ultimi N-1 elementi sono nella loro corretta

posizione e quindi l’intero vettore è ordinato. Inoltre, la

k-esima iterazione può essere limitata alle sole N-k posizioni. Grazie a

questo il costo di esecuzione su N elementi può essere espresso come:

C(BubS)= 2

Θ(N )

Pur realizzando la stessa complessità, tra il sequential sort e il bubble sort

esistono sostanziali differenze. Mentre il sequential sort ha costo

invariante rispetto ai dati, il bubble sort può terminare senza aver

compiuto tutte le N-2 iterazioni, come svantaggio però, mentre il

sequential sort richiede sempre N-1 swaps, il bubble sort ne può

richiedere

(N-1)(N-2)

void BubbleSort(int * V, int N, int * Perm)

{ int iter;

Boolean swap_found;

int count;

for(count=0; count<N; count++)

Perm[count]=count;

iter=0;

do

{ for(count=0, swap_found=FALSE; count<N-iter-1; count++)

{ if(V[Perm[count]]>V[Perm[count+1]])

{ swap(Perm, count, count+1)

swap_found=TRUE;

}

}

iter++;

}

while(swap_found==TRUE);

}

2.5.3 – Merge-sort

L’algoritmo di merge sort riduce il problema dell’ordinamento al problema

della fusione: due metà del vettore sono ordinate separatamente e poi

fuse in modo da ottenere un vettore ordinato globalmente.

Fusione

Il problema della fusione consiste nell’ordinare un vettore partizionato in

due semi-vettori ciascuno dei quali è inizialmente ordinato al suo interno.

Il semi-vettore sinistro viene inizialmente copiato su un semi-vettore di

appoggio, viene poi ripetutamente selezionato e trasferito sul vettore

complessivo il minimo del semi-vettore di appoggio e quello del

semi-vettore destro. L’algoritmo termina quando tutti gli elementi del

vettore di appoggio sono stati copiati sul vettore complessivo. L'algoritmo

esegue in tempo lineare rispetto alla lunghezza N del vettore

complessivo: ad ogni selezione e confronto tra due minimi, il vettore

complessivo cresce di un elemento, per cui l'algoritmo termina dopo un

numero massimo di N selezioni; d'altra parte, essendo i due semi-vettori

ordinati, la selezione e il confronto dei loro minimi avviene in tempo

costante. Al costo di selezione e copia dai due semi-vettori si aggiunge il

costo iniziale per copiare il semi-vettore sinistro nell'area di appoggio, che

l r

comunque avviene in tempo lineare. Gli indici ed indicano il numero di

elementi inizialmente contenuti nel semi-vettore di appoggio e in quello

destro che sono già stati selezionati e riportati nel

Dettagli
Publisher
A.A. 2023-2024
18 pagine
SSD Scienze matematiche e informatiche INF/01 Informatica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher aleandrea04 di informazioni apprese con la frequenza delle lezioni di Fondamenti di informatica e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Università degli Studi di Firenze o del prof Berretti Stefano.