Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Pag. 2
Non viene considerato neppure un costo di trasporto 0 esistente da una sede con se stessa nel calcolo della soluzione finale. Loutput viene pertanto espresso nella seguente forma per ogni coppia valida riscontrata: Il collegamento pi breve tra |sedeA| e |sedeB| ha costo |XXX| - sedeA e sedeB rappresentano i nomi delle sedi collegate da un cammino minimo, che potrebbe anche passare per altre sedi. - XXX rappresenta il costo minimo che unisce le due sedi. La forma in cui espresso loutput comunque una variante di quanto richiesto dalle specifiche, in cui viene supposto lutilizzo di una partenza e di una destinazione legate da un costo. Visto luso di un grafo non orientato (dettagliato meglio in seguito) in questo caso, si parla piuttosto di un collegamento minimo tra due punti in cui sorgente e destinazione sono interscambiabili, che quello che poi si evince dal formato di riga di standard output. La relazione che sfruttata tra lacquisizione dellinput e la generazione delloutput nasce dallimplementazione dellalgoritmo di Floyd-Warshall per la generazione di tutte le distanze minime possibili, lo stesso algoritmo inoltre genera la matrice dei padri grazie alla quale possibile determinare i cammini intermedi per ogni coppia, che non vengono comunque stampati in output in quanto non richiesti da specifiche. Loutput dei costi espresso in ordine crescente di costo tramite una funzione di stampa valori.
3. Progettazione
dellalgoritmo
Il
programma
costituito
da
3
sezioni
principali:
1) Acquisizione
dei
dati
da
file
e
definizione
di
una
struttura
a
grafo
per
il
contenimento
delle
informazioni
necessarie
quali:
nomi
delle
sedi
e
costi
diretti
di
trasporto.
2) Attraversamento
del
grafo
per
la
lettura
e
linserimento
dei
dati
nella
matrice
di
lavoro,
successiva
applicazione
dellalgoritmo
di
Floy-Warshall
per
il
calcolo
delle
distanze
minime
e
della
matrice
dei
padri
in
cui
vengono
determinati
i
punti
intermedi
del
percorso
minimo
tra
due
sedi.
3) Generazione
di
un
array
dinamico
di
strutture
definito
da
tutti
i
valori
validi
e
non
infiniti
ricavati
dalla
matrice
delle
distanze,
tale
array
sar
poi
ordinato
utilizzando
il
costo
minimo
come
parametro
chiave
di
ordinamento
in
quanto
richiesto
da
specifiche,
in
ordine
crescente.
Per
quanto
riguarda
la
gestione
degli
errori
di
memoria
che
potrebbero
essere
causati
dalla
funzione
malloc,
ho
preferito
interrompere
il
programma
con
listruzione
exit
(EXIT_FAILURE).
Listruzione
exit(),
secondo
le
General
information
about
the
exam
da
evitare
per
il
mantenimento
dei
principi
della
programmazione
strutturata.
Comunque
un
errore
derivante
da
uno
spazio
di
memoria
non
allocato
correttamente
non
avrebbe
portato
a
buon
fine
la
corretta
esecuzione
del
programma,
quindi
in
questo
caso
ho
preferito
andare
in
deroga
a
tale
regola.
Analizziamo
pi
in
dettaglio
le
tre
sezioni
in
cui
stato
diviso
il
programma:
-
Sezione
1:
i
dati
vengono
letti
dal
file
il
cui
nome
acquisito
come
parametro
dal
programma
stesso,
ogni
riga
contiene
il
collegamento
diretto
tra
due
sedi.
La
struttura
di
memoria
che
ho
scelto
di
utilizzare
per
il
contenimento
di
tutti
i
dati
un
grafo
la
cui
rappresentazione
avviene
tramite
una
struttura
dati
dinamica
a
lista
di
adiacenza,
i
vertici
della
lista
sono
le
sedi,
in
cui
oltre
al
nome
viene
salvato
anche
un
numero
di
successione,
mentre
gli
archi
di
collegamento
sono
i
costi
diretti
tra
i
vertici.
Le
sedi,
per
poter
essere
inserite
nella
lista
di
adiacenza,
vengono
analizzate
a
coppie
dalla
Pag. 3
funzione controlla_agigungi_sedi() in modo che nella stessa funzione si possa aggiungere anche larco che le collega con il peso del costo diretto acquisito in input. Dal grafo, contando il numero di vertici, so quante sedi differenti esistono, il dato non , infatti, noto a priori e servir per allocare dinamicamente la matrice delle distanze dirette richiesta da specifiche, nonch tutte le altre impiegate per il calcolo. Il numero di successione assegnato ad ogni sede e quindi ad ogni vertice del grafo, servir da puntatore per poter interagire con la matrice delle distanze, in quanto la posizione [i][j] sulla matrice indentificher anche i nomi delle sedi con il numero di successione i e j. La scelta del grafo come struttura di contenimento iniziale delle informazioni del file serve anche per evitare successivi accessi al disco. Poich lesistenza o no di un nome di sede deve essere controllata singolarmente, la problematica potrebbe essere risolta o con una continua scansione dei dati del file oppure con una continua scansione dei dati salvati in memoria tramite il grafo, con questultima sicuramente pi efficiente. I dati di ogni nuova sede trovata non sono inseriti con alcun criterio di ordinamento nella lista di adiacenza, linserimento serve solo per tenere traccia dei nomi di sede associandogli un indice, quindi ogni nuovo elemento assume un numero dindice incrementato di 1 rispetto al precedente. - Sezione 2: la lista di adiacenza creata mi fornisce alcuni dati utili, infatti, i vertici indicheranno il numero totale di sedi differenti che devo tenere in considerazione, il dato, come gi detto nella Sezione 1, viene utilizzato per allocare dinamicamente alcune matrici: Matrice di lavoro (ossia la matrice di adiacenza derivante dalla lista di adiacenza delle sedi). Matrice delle distanze, in cui verranno inseriti i dati calcolati con lalgoritmo di Floyd-Warshall. Matrice dei padri, che contiene il percorso relativo di passaggio per andare da una sede ad unaltra, questo anche il risultato richiesto dal punto due delle specifiche. La matrice di lavoro inizialmente settata con tutti i valori a infinito e la diagonale a 0 che infatti contiene il costo di ogni sede con se stessa, tramite unapposita funzione. Le altre due matrici, non vengono settate da nessuna funzione specifica ma la prima parte dellalgoritmo di Floyd-Warshall dedicato a tale scopo. Viene a questo punto attraversata la lista di adiacenza, ogni vertice analizzato sequenzialmente e per ogni vertice sono analizzati gli archi uscenti. I dati forniti dalloperazione saranno: il numero si successione associato al nome della sede da usare come indice per la matrice dei costi diretti; il collegamento tra la sede sorgente e la sede di destinazione, di cui posso leggere il numero di successione, che mi fornir il secondo indice da utilizzare con la matrice; il valore del peso salvato nellarco, ossia la distanza diretta tra due sedi. Una volta definita la matrice avente dimensione |n^2|, dove n il numero di vertici del grafo, viene applicato lalgoritmo di Floyd-Warshall, opportunamente modificato per poter trattare il valore infinito. Lalgoritmo di Floyd-Warshall si basa sulla soluzione del problema della chiusura transitiva di un grafo diretto, ovvero del problema di determinare lesistenza di un percorso per ogni coppia di vertici. Basandosi sul principio dellalgoritmo per la chiusura transitiva determina dist(i,j)(k) = min(dist(i,j)(k-1) , dist(i,k)(k-1) dist(k,j)(k-1)) calcolando i costi minimi tra due vertici analizzando tutti i possibili costi intermedi. Oltre a restituire come risultato le due matrici delle distanze minime e dei padri, restituisce, tramite la variabile locale contacoppie, il numero di collegamenti tra tutti i possibili vertici, che non abbiano una distanza infinita. Il dato serve per allocare correttamente il vettore di strutture che conterr lelenco delle coppie di percorso minimo e rappresenta il numero di linee delloutput finale.
Pag. 4
I dati numerici in termini di costo saranno poi estrapolati attraversando tutti gli elementi dalla matrice delle distanze, mentre i dati alfanumerici che identificano il nome della sede verranno estrapolati dalla lista di adiacenza grazie al numero di successione usato come indice. Come specificato anche nella sezione di analisi del problema, avendo considerato gli archi per andare da una sede allaltra a coppie simmetriche, generato un grafo non orientato che a sua volta genera una matrice delle distanze minime simmetrica, quindi solo la met dei dati contenuti nella matrice di pratica utilit e solo la met delle coppie sar inserita nel vettore di strutture poich laltra met contiene valori identici. Se il grafo fortemente connesso, in cui per ogni coppia di nodi v1 e v2 si ha che v1 connesso a v2, cio esiste sempre un cammino da v1 a v2, allora il numero n di vertici totali genera n^2 coppie di distanze minime in una matrice di Floyd-Warshall, tuttavia quello che dovr elaborare sar (n^2-n) / 2 , in quanto dovr scartare la diagonale che indica semplicemente che ogni elemento ha un costo nullo con se stesso, mentre del risultato, per simmetria prender solo met dei valori calcolati. Il test nr.9 descritto nel paragrafo di testing del programma si proporr di verificare quanto affermato. - Sezione 3: dopo aver allocato il vettore di strutture possibile copiare i dati dalla matrice delle distanze generata da Floyd-Warshall nel vettore stesso, la struttura stata creata in modo da poter contenere le due stringhe di caratteri dei nominativi delle sedi nonch il costo collegamento. I dati sono inseriti nel vettore dinamico di dimensione t in modo non ordinato e per poter raggiungere loutput richiesto viene applicato lalgoritmo di ordinamento heapsort al vettore, utilizzando come parametro il costo cresciente. Il vettore, dopo essere stato ordinato, viene stampato in una variante rispetto a quella richiesta da specifiche e determinata dalla struttura simmetrica della matrice, si nota che per rispettare la forma richiesta da specifiche sarebbe bastato stampare due volte la stessa stringa invertendo sorgente e destinazione. La scelta di un algoritmo di tipo heapsort deriva dalle sue stesse caratteristiche, in quanto lalgoritmo opera sul posto non richiedendo altra memoria, il ch in caso di grosse quantit di dati sarebbe gi intensivamente utilizzata per lallocazione delle tre matrici e della lista di adiacenza; infine lalgoritmo non risente del problema di degrado quadratico che avrei potuto ottenere nel caso peggiore usando lalgoritmo di quicksort. La complessit asintotica risultante dallordinamento, dato un numero di elementi t in input, dove t il numero di cammini totali che si possono verificare, non dipenderebbe dallo stato iniziale degli elementi e sarebbe pari a O(t*log t). Dato che t nel caso peggiore uguale a ((n^2)-n)/2, in quanto rapportato al numero di vertici n presi in input, il valore degli elementi della matrice simmetrica quadrata senza la diagonale, il costo dellheapsort nel caso pessimo, espresso in funzione degli n vertici anzich del numero t di cammini diventa O(n^2 * log n^2). Questo valore andrebbe a sommarsi ad una complessit lineare pari a O(n^2) derivante dallinserimento dei dati nel vettore ottenuti tramite lattraversamento della matrice[n][n]. Per lo studio della complessit completa del programma si rimanda allultimo paragrafo. I file di libreria scritti matrice.c e fw-odinamento.c, contengono le funzioni necessarie alla risoluzione dei sottoproblemi incontrati. In particolare il file matrice.c contiene le funzioni necessarie alla risoluzione della prima sezione, mentre il file fw-ordinamento contiene le funzioni necessarie alla risoluzione delle ultime due sezioni descritte, come limplementazione dellalgoritmo di Floyd- Warshall e dellalgoritmo di heapsort per lordinamento dei costi minimi tra tutte le coppie di sedi.
Pag. 5
4. Implementazione
dellalgoritmo
I
file
seguenti
sono
stati
compilati
per
il
testing
con:
gcc
version
4.6.1
(Ubuntu/Linaro
4.6.1-9ubuntu3).
-
nome
file:
mincost.c
/**********************************************************/ /* Programma per la ricerca dei percorsi minimi tra tutte */ /* le coppie di destinazioni valide che non risultino a */ /* consto infinito. */ /* Il programma, una volta identificati i cammini minimi */ /* li stampa in ordine crescente. */ /* Autore: Alberto Arvizzigno */ /* arvizzignoa@simail.it */ /* Matricola n. 237953 */ /* Data rilascio: 30 gennaio 2012 */ /**********************************************************/ #include #include #include #include <stdio.h> <stdlib.h> "matrice.h" "fw-ordinamento.h"
int main( int argc, char *argv[]) { /*---------------definizione variabili-----------------*/ char destinazione_a[MAXCHAR], destinazione_b[MAXCHAR]; float costo; int contatore_dim_matrice, contacoppie; float **matrice_lavoro=NULL , **distanze=NULL , **padri=NULL; sede_t *lista_sedi=NULL; struct lista_costi *lista_costi_coppie=NULL; /*--------------fine definizione variabili-------------*/ printf("\nApertura file: %s\n",argv[1]); FILE *file_dati = fopen ( argv[1],"r"); /* apertura file in lettura da argomento file */ if ( file_dati!= NULL) /*se il file dati valido */ { while (!feof(file_dati) { if (fscanf(file_dati, "%s %s %f", destinazione_a, destinazione_b , &costo) != EOF) /*EOF definito in stdio.h*/ /*lettura elementi salvati su file per compilazione matrice*/ /*gli elementi sono salvati nella forma: sedeA sedeB distanza */ /*se non siamo arrivati ancora alla fine del file allora contolla gli*/ /*elmenti dello stream*/ lista_sedi= controlla_aggiungi_sedi ( &contatore_dim_matrice, lista_sedi, destinazione_a , destinazione_b, costo); /*se la linea di file non vuota o invalida i dati letti vengono processati ed inseriti in una struttura a grafo */ }/* fine ciclo while fine lettura dati da file*/ /*--------------------------------------------------------*/ /* ALLOCAZIONE MEMORIA MATRICI NECESSARIE AL CALCOLO */ /* l'allocazione avviene dinamicamente */ /*--------------------------------------------------------*/ matrice_lavoro =alloca_matrice_nuovo_elemento(contatore_dim_matrice,matrice_lavoro); /*alloca la matrice di lavoro*/ distanze=alloca_matrice_nuovo_elemento(contatore_dim_matrice,distanze); /*alloca matrice distanze per algoritmo floydwarshall*/ padri=alloca_matrice_nuovo_elemento(contatore_dim_matrice,padri); /*alloca matrice dei padri per algoritmo floydwarshall*/ /*----------FINE BLOCCO ALLOCAZIONE MATRICI----------*/ setta_matrice(matrice_lavoro,INFINITO,contatore_dim_matrice); /*setting della matrice principale*/ /*tutti valori sono = INFINITO */ /*tranne la diagonale settata a 0*/
Pag. 6
crea_matrice_da_grafo(matrice_lavoro,lista_sedi); /*salvataggio dei dati prelevati dal file nella matrice di lavoro*/ /* considerando che il costo per andare da A a B uguale al costo per andare da B ad A la matrice risulta simmetrica con la diagonale =0 */ contacoppie = floyd_warshall(matrice_lavoro, distanze, padri, contatore_dim_matrice); /*calcolo della matrice delle distanze e della*/ /*matrice dei padri contenente tutte le posizioni intermedie.*/ /*La funzione restituisce il numero di coppie con distanza non nulla*/ /*che sono state trovate, serve per l'allocazione dell'array*/ /*di strutture e per la scrittura del risultato finale*/ lista_costi_coppie=genera_array_distanze_minime(distanze,contatore_dim_matrice,contacoppie,lista_s edi); /*inserimento dati della matrice di floyd-warshall nell'array di strutture */ /*contente tutte le coppie collegate con la distanza minima di collegamento*/ heapsort (lista_costi_coppie , contacoppie); /*utilizzo dell'heapsort per l'ordinamento*/ /*dell'array di strutture contente le coppie ed il costo minimo*/ stampa_lista_coppie (lista_costi_coppie, contacoppie); /*stampa risultati sedeA, sedeB, costo */ } else /*errore se il file dati non valido */ { printf ("\nInserire come parametro il nome file corretto da processare\n"); exit (EXIT_FAILURE); /* implementata in stdlib.h*/ }
/*libero la memoria occupata matrici liste e array di struttura*/ rilascia_matrice(matrice_lavoro,contatore_dim_matrice); rilascia_matrice(distanze,contatore_dim_matrice); rilascia_matrice(padri,contatore_dim_matrice); rilascia_grafo (lista_sedi, contatore_dim_matrice); rilascia_vett_strutt (lista_costi_coppie, contacoppie); return 0; /*ritorno main */ }
Pag. 7
/*-----------------------------------------*/ /*ridichiarazione delle funzioni esportate */ /*-----------------------------------------*/ extern sede_t *controlla_aggiungi_sedi (int *, sede_t *, char *, char *, float ); extern float **alloca_matrice_nuovo_elemento (int , float **); extern void crea_matrice_da_grafo ( float **, sede_t * ); extern void rilascia_matrice (float **, int ); extern void rilascia_grafo ( sede_t* , int); /*-----------------------------------------*/
/*-----------------------------------*/ /* dichiarazione funzioni utilizzate */ /*-----------------------------------*/ sede_t *controlla_aggiungi_sedi (int *, sede_t *, char *, char *, float ); sede_t* aggiungi_elemento ( sede_t *, char *, int *); void aggiungi_arco ( sede_t *, sede_t *, float); sede_t* cerca_elemento_lista (sede_t *,char *); float **alloca_matrice_nuovo_elemento (int , float **); void crea_matrice_da_grafo ( float **, sede_t * ); void rilascia_matrice (float **, int ); void rilascia_grafo ( sede_t* , int); /*----------------------------------------------------------------------------------------------*/ /* controlla l'esistenza della coppia di destinazioni se non esiste l'aggiunge e gli assegna un numero di successione*/ /*----------------------------------------------------------------------------------------------*/ sede_t* controlla_aggiungi_sedi (int *numero_succ, sede_t *sedi, char *nome_sedeA , char *nome_sedeB, float peso_costo) { sede_t *nuovasede=sedi, *sede_appoggioA , *sede_appoggioB , *src , *dst; if ( (strcmp(nome_sedeA, nome_sedeB)!=0) && (peso_costo>0) ) /*effettua alcuni controlli sui valori proposti ,se il controllo non viene passato la coppia di valori viene scartata, la coppia immessa non pu essere sorgente==destinazionee il peso minimo della coppia deve essere maggiore di 0*/ { if ((sede_appoggioA=cerca_elemento_lista(sedi,nome_sedeA))==NULL) /*la sedeA nuova*/ { nuovasede= aggiungi_elemento (nuovasede,nome_sedeA , numero_succ); /*se nuova viene aggiunta alla lista delle sedi*/ src=nuovasede;/*se il nominativo nuovo allora diventa la sorgente*/ } else src=sede_appoggioA; /* se il nominativo gi presente in elenco allora la src resta il vecchio elemento */ if ((sede_appoggioB=cerca_elemento_lista(sedi,nome_sedeB))==NULL) /*la sedeB nuova */ {
Pag. 8
nuovasede= aggiungi_elemento (nuovasede, nome_sedeB , numero_succ);/* se nuova viene aggiunta alla lista delle sedi */ dst=nuovasede; /*se il nominativo nuovo allora il nuovo nominativo diventa la destinazione*/ } else dst=sede_appoggioB;/*se il nominativo gi presente in elenco allora la src resta il vecchio elemento */ /* ATTENZIONE! IL COSTO PER ANDARE DA UNA SEDE ALL'ALTRA E' UGUALE IN ENTRAMBE LE DIREZIONI, QUESTO GENERA UNA MATRICE DI COSTI SIMMETRICA*/ /*poich sorgente e destinazione sono percorribili in entrambi i sensi vengono*/ /*aggiunti due archi di peso uguale uno dalla sorgente e uno dalla destinazione*/ aggiungi_arco(src,dst,peso_costo); /*inserimento costo da srd a dst */ aggiungi_arco(dst,src,peso_costo); /* inserimento costo da dst a src*/ } else /*se viene riscontato un errore il programma scarta il valore non considerandolo*/ printf ("\nTrovati valori errati, la coppia %s e %s con valore %.2f stata scartata\n",nome_sedeA,nome_sedeB,peso_costo); return nuovasede; } /*------------------fine funzione-----------------------------*/ /*-------------------------------------------*/ /*aggiunge l'elemento alla lista di adiacenza*/ /*l'elemento contiene il nome della sede */ /* ed il numero di successione attribuito */ /*-------------------------------------------*/ sede_t *aggiungi_elemento ( sede_t *lista_sedi, char *nome_sede, int *numero_successione) { /*dichiarazione variabili locali*/ sede_t *nuova_sede; nuova_sede = (sede_t *)malloc (sizeof(sede_t)); /*allocazione spazio struttura per inserimento vertice*/ nuova_sede->nome_sede = (char*)malloc(strlen(nome_sede)+1); /* allocazione spazio stringa infrastruttura*/ if ((nuova_sede == NULL) || (nuova_sede->nome_sede==NULL))/* in caso di errore*/ { printf ("Errore di allocazione in memoria dell'oggetto"); exit(EXIT_FAILURE); } nuova_sede->succ_p=NULL; strcpy ( nuova_sede->nome_sede , nome_sede );/* copia del nome della sede*/ nuova_sede->numero_successione = *numero_successione;/*numero di successione*/ nuova_sede->succ_p=lista_sedi;/*passa alla sede successiva*/ (*numero_successione)++;/*incremento del numero di succ per il prossimo inserimento*/ return nuova_sede; } /*------------fine funzione-------------*/ /*--------------------------------------------------------------*/ /*funzione per aggiungere un arco dinamicamente al nodo */ /*--------------------------------------------------------------*/ void aggiungi_arco ( sede_t *sede_list_src, sede_t *sede_list_dst, float peso) { /*dichiarazione variabili locali*/ peso_t *nuovo_arco=NULL; nuovo_arco= (peso_t *)malloc (sizeof(peso_t)); /* alloca arco da src a dst*/ if (nuovo_arco == NULL) /* se malloc restituisce NULL errore */ { printf ("Errore di allocazione oggetto in memoria"); exit(EXIT_FAILURE);
Pag. 9
} /*assegna i valori che mi servono al nuovo arco tra cui il peso ( costo )*/ nuovo_arco->peso = peso; /* assegna il peso all'arco*/ nuovo_arco->sede_dst=sede_list_dst; nuovo_arco->peso_successivo=NULL; /*determino i puntatori del nuovo arco*/ if (sede_list_src->collega_pesi==NULL) sede_list_src->collega_pesi=nuovo_arco; else { nuovo_arco->peso_successivo=sede_list_src->collega_pesi->peso_successivo; sede_list_src->collega_pesi->peso_successivo=nuovo_arco; }} /*----------------------------------*/ /*-----------fine funzione----------*/ /*----------------------------------*/ /*---------------------------------------------------*/ /* Funzione di ricerca elemento */ /* ritorna l'elemento se l'elemento nella lista */ /* altrimenti NULL se non lo trova */ /*---------------------------------------------------*/ sede_t *cerca_elemento_lista (sede_t *nodo,char *nome_sede_cmp) { /*definizione variabili locali*/ sede_t *punta=nodo; /*---------------------------*/ for(punta=nodo; (punta!=NULL) ;punta=punta->succ_p) { /*se trova il valore esce subitop dal ciclo restituiendo la posizione nella lista*/ if (strcmp( punta->nome_sede, nome_sede_cmp)==0) return punta; } return punta; } /*-------------*/ /*fine funzione*/ /*-------------*/ /* --------------------------------------------------*/ /* alloca la matrice dinamica definita da n elementi */ /* --------------------------------------------------*/ float **alloca_matrice_nuovo_elemento (int num_elementi_matrice, float **matrice) { /*dichiarazione variabili locali*/ int i; /* allocazione matrice quadrata contenete num_elementi_matrice*/ matrice = (float **)malloc((num_elementi_matrice)*(sizeof (float*))); if (matrice == NULL) /* se malloc restituisce NULL errore */ { printf ("Errore di allocazione oggetto in memoria"); exit(EXIT_FAILURE); } for (i=0;i<num_elementi_matrice;i++) { matrice[i]=(float*)malloc(num_elementi_matrice*sizeof(float)); if (matrice[i] == NULL) /* se malloc restituisce NULL errore */ { printf ("Errore di allocazione oggetto in memoria"); exit(EXIT_FAILURE); }} return matrice; } /*-------------*/ /*fine funzione*/ /*-------------*/
Pag. 10
/*------------------------------------------------*/ /*visita la lista di adiacenza per l'ottenimento */ /*della matrice di adiacenza */ /*------------------------------------------------*/ void crea_matrice_da_grafo ( float **matrice, sede_t *lista_sedi) { /*definizione variabili locali */ sede_t* punta=lista_sedi; peso_t *costi; /*-----------------*/ /* la crezione della matrice di adiacenza avviene attraversando sequenzialmente i vertici della lista di adiacenza e per ogni vertice vengono attraversati gli archi che ne fanno parte, durante l'attraversamento i dati vengono copiati nella matrice di adiacenza */ for (; punta!=NULL ;punta=punta->succ_p) { costi=punta->collega_pesi; for ( ;costi!=NULL ; costi= costi->peso_successivo) /*scorro la lista di adiacenza*/ matrice[punta->numero_successione][costi->sede_dst->numero_successione]=costi->peso;/*inserisco nella matrice il valore prelevando dati e indici dalla lista di adiacenza*/ }} /*----------fine funzione----------*/ /*--------------------------------------------------------*/ /*funzioni di rilascio memoria allocata per matrice e grafo*/ /*--------------------------------------------------------*/ void rilascia_matrice (float **matrice, int num_elementi_matrice) { int i; { for (i=0;i<num_elementi_matrice;i++) free(matrice[i]); } free(matrice); } /* attraverso il grafo eliminando archi e vertici */ void rilascia_grafo ( sede_t* nodo, int elementi) { for(; (nodo!=NULL) ;nodo=nodo->succ_p) { for(;(nodo->collega_pesi!=NULL); nodo->collega_pesi=nodo->collega_pesi->peso_successivo); free(nodo->collega_pesi); free(nodo); } } /*fine funzione*/
Pag. 11
/*ridichiarazioni delle funzioni esportate specifiche per */ /*l'algoritomo di Floyd-Warshall e per l'ordinamento costi minimi*/ extern int floyd_warshall(float **, float **, float **, int ); extern void setta_matrice ( float **, int , int ); extern struct lista_costi* genera_array_distanze_minime( float **, int ,int, sede_t *); extern void stampa_lista_coppie (struct lista_costi[] , int); extern void heapsort (struct lista_costi [], int ); extern void rilascia_vett_strutt (struct lista_costi *, int);
/*----------------------------------------------------*/ /*dichiarazioni di funzioni specifiche per l'algoritmo*/ /*di Floyd-Warshall e per l'ordinamento costi minimi */ /*----------------------------------------------------*/ int floyd_warshall(float **, float **, float **, int ); void setta_matrice ( float **, int , int ); struct lista_costi* genera_array_distanze_minime( float **, int ,int, sede_t *); void stampa_lista_coppie (struct lista_costi* , int); void heapsort (struct lista_costi*, int ); void sieve_heap (struct lista_costi*, int , int ); void rilascia_vett_strutt (struct lista_costi*, int); /*----------------------------------------------------*/ /*---------------------------------------------------------------*/ /*calcola la matrice delle distanze tra tutte le coppie di valori*/ /* la funzione con l'algoritmo di floyd warshall stata */ /* modificata per poter utlizzare -1 come valore infinito */ /* inoltre conta le coppie di valori con un cammino non INFINITO */ /*---------------------------------------------------------------*/ int floyd_warshall (float **matrice_lavoro, float **distanze, float **padri, int numero_vertici) { /*dichiarazione variabili locali*/ int i,j, k, contacoppie=0, precedente, inf=0; /*variabile inf serve per contare il numero di infiniti presenti*/ /*-----------------------------*/ /*implementazione dell'algoritmo di floy-warshall come da lezione numero 27 opportunamente modificato per la gestione del costo infinito rappresentato da INFINITO= -1*/ for (i = 0; (i < numero_vertici); i++) for (j = 0; (j < numero_vertici); j++) { distanze[i][j] = matrice_lavoro[i][j]; if (distanze[i][j]==INFINITO) inf++; /*quanti valori di INFINITO
Pag. 12
c'erano prima del calcolo?*/ padri[i][j] = (matrice_lavoro[i][j] != INFINITO)? i: -1; } for (k = 0; (k < numero_vertici);k++) { for (i = 0; (i < numero_vertici);i++) { for (j = 0; (j < numero_vertici);j++) { precedente=distanze[i][j]; /*l'algoritmo di f-w prevede la possibilit di usare pesi negativi, tuttavia la costante INFINITO che viene usata = -1, quindi se da una parte utile per la facilit d'impiego dall'altra ho bisogno di inserire alcuni step di controllo in pi per verificare il caso INFINITO che non altro che un numero negativo e non deve essere messo a calcolo nella funzione.*/ if (((distanze[i][k]!=INFINITO) && (distanze[k][j]!=INFINITO)) && distanze[i][j]==INFINITO) /*tratta la logica del caso infinito */ { distanze[i][j] = distanze[i][k] + distanze[k][j]; padri[i][j] = padri[k][j]; } else if ((distanze[i][k]!=INFINITO) && (distanze[k][j]!=INFINITO)) /* tratta la logica del caso infinito*/ if (distanze[i][j] > distanze[i][k] + distanze[k][j]) /* se la distanza maggiore viene rimpiazzata con la minore della triangolazione */ { distanze[i][j] = distanze[i][k] + distanze[k][j]; padri[i][j] = padri[k][j]; } if ((precedente==INFINITO) && (distanze[i][j]!=INFINITO)) inf--;/*quante coppie INFINITO sono scomparse dopo aver applicato f-w?*/ }}} contacoppie=((numero_vertici)*(numero_vertici)-numero_vertici-inf)/2; /* il numero di coppie calcolato in questo modo*/ /*[(tutti i vertici)^2 - diagonale - n.ro coppie tot INF]/2 */ /*la matrice simmetrica quindi prendo solo met del valore*/ return contacoppie; } /*-------------fine funzione floyd-warshall----------------------*/ /*-------------------------------------------------------------*/ /*funzione di settaggio matrice imposta il valore iniziale ad */ /*INFINITO e lo 0 sulla diagonale */ /*-------------------------------------------------------------*/ void setta_matrice ( float **matrice, int valore_sett , int elementi) { int i,j; for(i = 0; i < elementi; i++) { for(j = 0; j < elementi; j++) if (j==i) matrice[j][j]=0; else matrice[j][i]=INFINITO; } } /*-------------------fine funzione------------------*/ /*--------------------------------------------------------------*/ /*estrapolazione delle distanze minime dalla matrice calcolata */ /*con floyd-warshall, inserimento dei valori estrapolati */ /*in una lista non ordinata */ /*--------------------------------------------------------------*/ struct lista_costi * genera_array_distanze_minime( float **matrice, int elementi, int contacoppie, sede_t *lista_sedi_supp)
Pag. 13
{ /*variabili interno funzione*/ sede_t * lista_sedi_RIG, *lista_sedi_COL; struct lista_costi *indice; int i,j,k=1; /*---------------------------*/ contacoppie++;/* incrementa numero per dare spazio alla posizione 0 del vettore usata dall'heap*/ indice= (struct lista_costi*)malloc(contacoppie*sizeof(struct lista_costi)); /*alloca elemento array[0] di struttura per la funzione heap*/ /* il vettore[0] da tenere vuoto */ indice[0].nome_sede_a = (char*)malloc(MAXCHAR*sizeof(char)); indice[0].nome_sede_b = (char*)malloc(MAXCHAR*sizeof(char)); /*----------------------------------------------------------*/ for (i=0, lista_sedi_RIG=lista_sedi_supp; (i<elementi) ;i++, lista_sedi_RIG=lista_sedi_RIG>succ_p) /*scansione delle righe della matrice e della lista*/ { for (j=i+1, lista_sedi_COL=lista_sedi_RIG->succ_p; (j<elementi) ;j++, lista_sedi_COL=lista_sedi_COL->succ_p) /*scansione delle colonne della matrice e della lista*/ if(matrice[elementi-1-i][elementi-1-j]!=INFINITO)/* se l'elemento nella matrice non infinito alloca salvalo nel vettore*/ { indice[k].nome_sede_a = (char*)malloc((strlen(lista_sedi_RIG->nome_sede)+1));/*allocazione memoria stringa*/ indice[k].nome_sede_b = (char*)malloc((strlen(lista_sedi_COL->nome_sede)+1));/*allocazione memoria stringa*/ strcpy ( indice[k].nome_sede_a , lista_sedi_RIG->nome_sede );/*copia la stringa della sede dalla lista di adiacenza puntato dalla RIGA nell'elemento del vettore di struttre*/ strcpy ( indice[k].nome_sede_b , lista_sedi_COL->nome_sede );/*copia la stringa della sede dalla lista di adiacenza puntato dalla COLONNA nell'elemento del vettore di struttre*/ indice[k].costo= matrice[elementi-1-i][elementi-1-j]; k++; }} return indice; /* restituisce il vettore di strutture */ } /*---------------fine funzione--------------------*/ /* --------------------------------*/ /* stampa il vettore di strutture */ /*---------------------------------*/ void stampa_lista_coppie (struct lista_costi *indice, int contacoppie) { /*variabili interno funzione*/ int i; for (i=1;i<=contacoppie;i++) printf(" \n Il collegamento pi breve tra |%s| e |%s| ha costo |%.2f|\n", indice[i].nome_sede_a, indice[i].nome_sede_b, indice[i].costo); printf("\n|----------------fine lista raggiunta ------------------|\n"); /*-------fine funzione-------------*/ /*---------------------------------*/ /* heap sort per ordinamento lista */ /* la posizione index[0] vuota */ /* come da lezione nr.04.11 */ /*---------------------------------*/ void heapsort(struct lista_costi *index, int elementi) { int sinistra, destra; struct lista_costi tmp; tmp.nome_sede_a = (char*)malloc(MAXCHAR*sizeof(char)); tmp.nome_sede_b = (char*)malloc(MAXCHAR*sizeof(char));
Pag. 14
/* trasformo l'array in heap */ for (sinistra = elementi / 2;(sinistra >= 1); sinistra--) sieve_heap(index, sinistra, elementi); for (destra = elementi;(destra > 1); destra--) { /* tmp = index[1] */ strcpy (tmp.nome_sede_a , index[1].nome_sede_a) ; strcpy (tmp.nome_sede_b , index[1].nome_sede_b) ; tmp.costo=index[1].costo; /*index[1]=index[destra]*/ strcpy (index[1].nome_sede_a , index[destra].nome_sede_a); strcpy (index[1].nome_sede_b , index[destra].nome_sede_b); index[1].costo=index[destra].costo; /*index[destra] = tmp;*/ strcpy (index[destra].nome_sede_a , tmp.nome_sede_a); strcpy (index[destra].nome_sede_b , tmp.nome_sede_b); index[destra].costo=tmp.costo; sieve_heap(index,1,destra-1); }} /*-------------------------------------------*/ /*---------------------------------------------*/ /*implementazione dell'algoritmo di heapsort */ /*opportumanete modificato per gestire un */ /*vettore di strutture come da lezione nr.04.11*/ /*---------------------------------------------*/ void sieve_heap(struct lista_costi *index , int sinistra, int destra) { int i, j; struct lista_costi nuovo; /*allocazione della struttura nuovo utile per gli scambi*/ nuovo.nome_sede_a = (char*)malloc(MAXCHAR*sizeof(char)); nuovo.nome_sede_b = (char*)malloc(MAXCHAR*sizeof(char)); for ( nuovo.costo = index[sinistra].costo, strcpy (nuovo.nome_sede_a , index[sinistra].nome_sede_a), strcpy (nuovo.nome_sede_b , index[sinistra].nome_sede_b), i=sinistra , j=2*i ; (j <= destra);)
{ if ((j < destra) && (index[j + 1].costo > index[j].costo)) j++; if (nuovo.costo < index[j].costo) { strcpy (index[i].nome_sede_a, index[j].nome_sede_a); strcpy (index[i].nome_sede_b, index[j].nome_sede_b); index[i].costo = index[j].costo; i = j; j = 2 * i; } else j = destra + 1; } if (i != sinistra) { strcpy (index[i].nome_sede_a, nuovo.nome_sede_a); strcpy (index[i].nome_sede_b, nuovo.nome_sede_b); index[i].costo = nuovo.costo; } } /*--------fine funzione-------------------------*/ /*--------------------------------------------*/ /*rilascia la memoria del vettore di strutture*/
Pag. 15
/*--------------------------------------------*/ void rilascia_vett_strutt (struct lista_costi *index, int contacoppie) { int i=0; for (;i<=contacoppie;i++) { free (index[i].nome_sede_a); free (index[i].nome_sede_b); } free (index); } /*-----------------fine funzione-------------------*/
Inizio compilazione files $(PAROGG) $(LIBFILEC) $(PAROGG) $(OUT).c $(PARMAIN) $(OUT) $(OUT).o $(LIBFILEO)
Pag. 16
Pag. 17
|----------------fine lista raggiunta ------------------| -Test nr. 3: errore di inserimento per distanza negativa dati in input file:test2.txt sedea sedeb 100 sedea sedec -10 ./mincost test2.txt Trovati valori errati, la coppia sedea e sedec con valore -10.00 stata scartata Il collegamento pi breve tra |sedeb| e |sedea| ha costo |100.00| |----------------fine lista raggiunta ------------------| Nota: il programma non inserisce la coppia in quanto il costo in euro negativo ma inserisce solo il dato valido. -Test nr. 4: prova centesimi, verifico solo loutput corretto con un dato in centesimi dati in input file:test3.txt sedea sedeb 1000.50 ./mincost test3.txt Il collegamento pi breve tra |sedeb| e |sedea| ha costo |1000.50| |----------------fine lista raggiunta ------------------| -Test nr. 5: prova centesimi, verifico solo loutput corretto con pi dati in centesimi dati in input file:test5.txt sedea sedeb 1000 sedea sedeZ 100.5 sedeZ sedeK 200.7 ./mincost test5.txt Il collegamento pi breve tra |sedeZ| e |sedea| ha costo |100.50| Il collegamento pi breve tra |sedeK| e |sedeZ| ha costo |200.70| Il collegamento pi breve tra |sedeK| e |sedea| ha costo |301.20| Il collegamento pi breve tra |sedeb| e |sedea| ha costo |1000.00| Il collegamento pi breve tra |sedeZ| e |sedeb| ha costo |1100.50| Il collegamento pi breve tra |sedeK| e |sedeb| ha costo |1301.20| |----------------fine lista raggiunta ------------------|
Pag. 18
./mincost test4.txt Il collegamento pi breve tra |w2| e |w1| ha costo |1.00| Il collegamento pi breve tra |d| e |e| ha costo |1.00| Il collegamento pi breve tra |f| e |z| ha costo |1.00| Il collegamento pi breve tra |z| e |a| ha costo |2.00| Il collegamento pi breve tra |k| e |f| ha costo |2.00| Il collegamento pi breve tra |d| e |r| ha costo |2.00| Il collegamento pi breve tra |k| e |z| ha costo |3.00| Il collegamento pi breve tra |y| e |u| ha costo |3.00| Il collegamento pi breve tra |r| e |e| ha costo |3.00| Il collegamento pi breve tra |f| e |a| ha costo |3.00| Il collegamento pi breve tra |d| e |y| ha costo |4.00| Il collegamento pi breve tra |b| e |a| ha costo |4.00| Il collegamento pi breve tra |q| e |l| ha costo |5.00| Il collegamento pi breve tra |c| e |b| ha costo |5.00| Il collegamento pi breve tra |k| e |a| ha costo |5.00|
Pag. 19
Il collegamento pi breve tra |q| e |b| ha costo |5.00| Il collegamento pi breve tra |y| e |e| ha costo |5.00| Il collegamento pi breve tra |z| e |b| ha costo |6.00| Il collegamento pi breve tra |r| e |y| ha costo |6.00| Il collegamento pi breve tra |v| e |q| ha costo |6.00| Il collegamento pi breve tra |f| e |b| ha costo |7.00| Il collegamento pi breve tra |d| e |u| ha costo |7.00| Il collegamento pi breve tra |e| e |z| ha costo |7.00| Il collegamento pi breve tra |f| e |e| ha costo |8.00| Il collegamento pi breve tra |d| e |z| ha costo |8.00| Il collegamento pi breve tra |t| e |r| ha costo |8.00| Il collegamento pi breve tra |u| e |e| ha costo |8.00| Il collegamento pi breve tra |c| e |a| ha costo |9.00| Il collegamento pi breve tra |r| e |u| ha costo |9.00| Il collegamento pi breve tra |q| e |c| ha costo |9.00| Il collegamento pi breve tra |d| e |f| ha costo |9.00| Il collegamento pi breve tra |k| e |b| ha costo |9.00| Il collegamento pi breve tra |e| e |a| ha costo |9.00| Il collegamento pi breve tra |q| e |a| ha costo |9.00| Il collegamento pi breve tra |l| e |k| ha costo |10.00| Il collegamento pi breve tra |d| e |a| ha costo |10.00| Il collegamento pi breve tra |k| e |e| ha costo |10.00| Il collegamento pi breve tra |r| e |z| ha costo |10.00| Il collegamento pi breve tra |d| e |t| ha costo |10.00| Il collegamento pi breve tra |l| e |b| ha costo |10.00| Il collegamento pi breve tra |v| e |b| ha costo |11.00| Il collegamento pi breve tra |z| e |c| ha costo |11.00|
Pag. 20
Il collegamento pi breve tra |q| e |z| ha costo |11.00| Il collegamento pi breve tra |r| e |f| ha costo |11.00| Il collegamento pi breve tra |v| e |l| ha costo |11.00| Il collegamento pi breve tra |t| e |e| ha costo |11.00| Il collegamento pi breve tra |d| e |k| ha costo |11.00| Il collegamento pi breve tra |l| e |f| ha costo |12.00| Il collegamento pi breve tra |f| e |c| ha costo |12.00| Il collegamento pi breve tra |q| e |f| ha costo |12.00| Il collegamento pi breve tra |y| e |z| ha costo |12.00| Il collegamento pi breve tra |r| e |a| ha costo |12.00| Il collegamento pi breve tra |l| e |z| ha costo |13.00| Il collegamento pi breve tra |y| e |f| ha costo |13.00| Il collegamento pi breve tra |e| e |b| ha costo |13.00| Il collegamento pi breve tra |r| e |k| ha costo |13.00| Il collegamento pi breve tra |d| e |b| ha costo |14.00| Il collegamento pi breve tra |k| e |c| ha costo |14.00| Il collegamento pi breve tra |q| e |k| ha costo |14.00| Il collegamento pi breve tra |y| e |a| ha costo |14.00| Il collegamento pi breve tra |t| e |y| ha costo |14.00| Il collegamento pi breve tra |l| e |a| ha costo |14.00| Il collegamento pi breve tra |l| e |c| ha costo |14.00| Il collegamento pi breve tra |h| e |d| ha costo |15.00| Il collegamento pi breve tra |v| e |c| ha costo |15.00| Il collegamento pi breve tra |u| e |z| ha costo |15.00| Il collegamento pi breve tra |y| e |k| ha costo |15.00| Il collegamento pi breve tra |v| e |a| ha costo |15.00| Il collegamento pi breve tra |r| e |b| ha costo |16.00| Il collegamento pi breve tra |h| e |e| ha costo |16.00|
Pag. 21
Il collegamento pi breve tra |u| e |f| ha costo |16.00| Il collegamento pi breve tra |v| e |z| ha costo |17.00| Il collegamento pi breve tra |u| e |a| ha costo |17.00| Il collegamento pi breve tra |t| e |u| ha costo |17.00| Il collegamento pi breve tra |h| e |r| ha costo |17.00| Il collegamento pi breve tra |e| e |c| ha costo |18.00| Il collegamento pi breve tra |q| e |e| ha costo |18.00| Il collegamento pi breve tra |u| e |k| ha costo |18.00| Il collegamento pi breve tra |y| e |b| ha costo |18.00| Il collegamento pi breve tra |v| e |f| ha costo |18.00| Il collegamento pi breve tra |t| e |z| ha costo |18.00| Il collegamento pi breve tra |d| e |c| ha costo |19.00| Il collegamento pi breve tra |q| e |d| ha costo |19.00| Il collegamento pi breve tra |t| e |f| ha costo |19.00| Il collegamento pi breve tra |h| e |y| ha costo |19.00| Il collegamento pi breve tra |l| e |e| ha costo |20.00| Il collegamento pi breve tra |v| e |k| ha costo |20.00| Il collegamento pi breve tra |t| e |a| ha costo |20.00| Il collegamento pi breve tra |u| e |b| ha costo |21.00| Il collegamento pi breve tra |d| e |l| ha costo |21.00| Il collegamento pi breve tra |q| e |r| ha costo |21.00| Il collegamento pi breve tra |r| e |c| ha costo |21.00| Il collegamento pi breve tra |t| e |k| ha costo |21.00| Il collegamento pi breve tra |h| e |u| ha costo |22.00| Il collegamento pi breve tra |l| e |r| ha costo |23.00| Il collegamento pi breve tra |y| e |c| ha costo |23.00| Il collegamento pi breve tra |q| e |y| ha costo |23.00|
Pag. 22
Il collegamento pi breve tra |h| e |z| ha costo |23.00| Il collegamento pi breve tra |v| e |e| ha costo |24.00| Il collegamento pi breve tra |h| e |f| ha costo |24.00| Il collegamento pi breve tra |t| e |b| ha costo |24.00| Il collegamento pi breve tra |l| e |y| ha costo |25.00| Il collegamento pi breve tra |h| e |a| ha costo |25.00| Il collegamento pi breve tra |v| e |d| ha costo |25.00| Il collegamento pi breve tra |h| e |t| ha costo |25.00| Il collegamento pi breve tra |u| e |c| ha costo |26.00| Il collegamento pi breve tra |q| e |u| ha costo |26.00| Il collegamento pi breve tra |h| e |k| ha costo |26.00| Il collegamento pi breve tra |v| e |r| ha costo |27.00| Il collegamento pi breve tra |l| e |u| ha costo |28.00| Il collegamento pi breve tra |h| e |b| ha costo |29.00| Il collegamento pi breve tra |q| e |t| ha costo |29.00| Il collegamento pi breve tra |t| e |c| ha costo |29.00| Il collegamento pi breve tra |v| e |y| ha costo |29.00| Il collegamento pi breve tra |l| e |t| ha costo |31.00| Il collegamento pi breve tra |v| e |u| ha costo |32.00| Il collegamento pi breve tra |h| e |c| ha costo |34.00| Il collegamento pi breve tra |q| e |h| ha costo |34.00| Il collegamento pi breve tra |v| e |t| ha costo |35.00| Il collegamento pi breve tra |h| e |l| ha costo |36.00| Il collegamento pi breve tra |v| e |h| ha costo |40.00| |----------------fine lista raggiunta ------------------|
-Test
nr.
7:
verifica
errori
dati
in
input
dati
in
input
file:test6.txt
a
a
10
b
b
10
Pag. 23
./mincost test6.txt Trovati valori errati, la coppia a e a con valore 10.00 stata scartata Trovati valori errati, la coppia b e b con valore 10.00 stata scartata |----------------fine lista raggiunta ------------------| -Test nr. 8: verifica errori dati in input dati in input file:test7.txt a b 10 a a 20 z g -10 ./mincost test7.txt Trovati valori errati, la coppia a e a con valore 20.00 stata scartata Trovati valori errati, la coppia z e g con valore -10.00 stata scartata Il collegamento pi breve tra |b| e |a| ha costo |10.00| |----------------fine lista raggiunta ------------------| -Test nr. 9: verifica dati in un grafo fortemente connesso. Prima di procedere alla verifica utile sapere cosa aspettarsi. Se il mio grafo fortemente connesso composto da V elementi allora il numero di righe che mi dovr aspettare in output (V^2-V) / 2. Nel caso proposto ho V=4 quindi il numero di righe sar di (16-4)/2=6 che rappresenta tutti i cammini possibili. Quindi mi aspetter 6 righe. dati in input file:test8.txt a b 1 a c 2 a d 3 b c 4 b d 5 c d 6 ./mincost test8.txt Il collegamento pi breve tra |b| e |a| ha costo |1.00| Il collegamento pi breve tra |c| e |a| ha costo |2.00| Il collegamento pi breve tra |d| e |a| ha costo |3.00| Il collegamento pi breve tra |c| e |b| ha costo |3.00| Il collegamento pi breve tra |d| e |b| ha costo |4.00| Il collegamento pi breve tra |d| e |c| ha costo |5.00|
Pag. 24
|----------------fine lista raggiunta ------------------| -Test nr. 10: verifica dati nel caso in cui la componente connessa sia rappresentata solo dalla coppia. In input abbiamo 4 coppie di valori scollegate dalle altre, quindi dovremmo aspettarci un output di 4 linee corrispondenti alle distanze minime dellinput. dati in input file:test9.txt a b 5 c d 10 e f 15 g h 20 ./mincost test9.txt Il collegamento pi breve tra |b| e |a| ha costo |5.00| Il collegamento pi breve tra |d| e |c| ha costo |10.00| Il collegamento pi breve tra |f| e |e| ha costo |15.00| Il collegamento pi breve tra |h| e |g| ha costo |20.00| |----------------fine lista raggiunta ------------------|
Pag. 25
Pag. 26
che la seconda ricerca danno esito negativo ed entrambi gli elementi sono da aggiungere alla lista in quanto nuovi. Il risultato della funzione nel caso pessimo, effettuando la sostituzione n1=n+1 sar dunque T(n)=6n+50. Quindi controlla_aggiungi_sedi(), chiamata singolarmente, risulterebbe di complessit asintotica pari a O(n) e strettamente collegata con il numero totale di sedi differenti trovate nel file. Funzione alloca_matrice_nuovo_elemento() Tale funzione, che serve per allocare una matrice di n elementi, nuovamente proporzionale a n, ossia al numero di vertici distinti appartenenti al grafo, in quanto per ogni ciclo for viene allocato un intero blocco corrispondente a n elementi. Il ciclo for viene iterato per n volte, quindi risulta che T(n)=1+(n)*(1+1+1)+1=3n+2. Tale funzione che viene chiamata tre volte per lallocazione dei dati, ha comunque una complessit asintotica pari a O(n). Funzione setta_matrice() La funzione costituita da due cicli for annidiati che devono settare gli elementi della matrice quadrata. Il calcolo della complessit risulta T(n)=1+n(1+n(1+1+1+1)+1+1)=4n^2+3n+1 =O(n^2) , con n sedi. Funzione crea_matrice_da_grafo() La funzione ha lo scopo di attraversare la lista di adiacenza per poter cos creare la matrice di adiacenza. Sul calcolo della complessit di questa funzione giocano due fattori: il numero di vertici e la quantit di archi che ha ogni vertice. Tuttavia ogni vertice n che appartenga allinsieme di vertici V pu avere al massimo V-1 archi di collegamento. Il caso peggiore quindi sar intuitivamente rappresentato dalla massimizzazione del numero di archi per ogni vertice. Con n vertici in input avremo una complessit asintotica che tender a n*(n-1) e quindi pari a O(n^2)). Dal calcolo del caso pessimo, in cui il numero di archi sia pari (n-1) vertici, risulta T(n)=1+1+n(1+(n-1)(1+1+1))= 3n^2- 2n+2=O(n^2) come da ipotesi intuitiva. Il caso ottimo invece si verifica quando ogni vertice connesso solo con un altro vertice e con nessun altro, il che trasformerebbe la precedente in T(n)=1+1+n(1+1*2)=3n+2=O(n). Quindi se i vertici sono poco connessi, abbiamo una crescita lineare allaumentare dei vertici, se i vertici sono fortemente connessi allora abbiamo una complessit con crescita quadratica. Funzione floyd-warshall()
La funzione che stata utilizzata quella della lezione 07.09, in cui vengono modificati alcuni aspetti in modo che possa essere adattata al caso specifico. La funzione originale poteva acquisire anche numeri negativi, questa stata modificata per poter utilizzare il numero -1 come valore rappresentante linfinito. Inoltre la funzione restituisce il numero di coppie collegate che sono state riscontrate, i dato servir poi per altre funzioni descritte in seguito. La complessit asintotica per un numero , derivante dallannidiamento di tre cicli for pari a O(n^3). Allinterno dellintero programma la complessit che ha un maggior peso, quindi risulter alla fine larmonica dominante nel calcolo generale. Lalgoritmo della funzione diviso in due parti principali. La prima parte costituita da due cicli for annidiati in cui la matrice di lavoro viene copiata nella matrice delle distanze e la matrice dei padri viene settata. La complessit per questa parte T(n)=1+(n)(1+1+(n)(1+1+1+1+1)+1)=5n^2- 10n+2=O(n^2). Quasto risultato va poi a sommarsi allalgoritmo vero e proprio di determinazione delle distanze minime che ha una complessit nel caso pessimo pari a: T(n)=1+(n)(1+1+(n)(1+1+(n)(1+1+1+1+1+1+1+1+1+1+1)))+1+1= 11n^3+2n^2+2n+3=O(n^3). Quindi consideriamo la complessit asintotica di tutta la funzione pari al valore O(n^3) ossia cubica.
Pag. 27
Funzione genera_array_distanze_minime() La funzione ha lo scopo di riempire il vettore di strutture in modo non ordinato, per poter assolvere il compito viene attraversata la lista di adiacenza con due cicli for annidiati, tuttavia il secondo ciclo parte dallelemento a cui si fermato il ciclo pi esterno. Questo procedimento d origine a n*n/2 interazioni, nel ciclo pi interno viene infatti calcolata la media di iterazioni effettuate. Intuitivamente la complessit asintotica sar quindi pari a O(n^2) mentre il procedimento porta a prendere in considerazione esattamente met della matrice delle distanze, infatti si gi precedentemente spiegato che laltra met simmetrica. Effettuando il calcolo otteniamo T(n)=1+1+1+1+2+n(1+1+2+n/2(1+1+6))+1 = 4n^2+4n+7=O(n^). Funzione heapsort() Lalgoritmo di heapsort di tipo non stabile, ma che opera sul posto, non dipende dalla posizione dei dati iniziali e loperazione di setacciamento proporzionale allaltezza dellalbero binario associatavi. Usando la soluzione proposta nella lezione 04.11 attinente lheapsort, possiamo osservare il calcolo della complessit. Poich Il tempo di settaciamento dellheap proporzionale allaltezza dellalbero binario ad esso associato, dato che tale albero bilanciato, il valore sar O(log t). Il calcolo della complessit pu essere applicato al programma, bisogna tenere per in considerazione che se per scambiare un valore con lheap fatto di interi ho un costo unitario, nel caso del vettore di strutture che contiene i due nomi delle sedi nonch il costo minimo di trasporto, devono essere scambiati tutti e tre gli elementi. La valutazione asintotica dellalgoritmo O(t*log t). Dal calcolo risulta T(t)=1+2+(t/2)(1+log t +1)+1+1+(t-1)(1+3+3+3+log t +1)+1=1.5 t log t+12t-5 pari quindi a O(t log t). Per massimizzare t applico t=(n^2-n)/2 da cui la complessit pessima in funzione di n diventa T(n)=1.5*(n^2-n)/2 * log (n^2-n)/2 + 12 (n^2-n)/2 5 =O(n^2*log n^2) Funzioni di stampa vettore di rilascio memoria La funzione che si occupa della stampa dei risultati la funzione stampa_lista_coppie(), costituita da un semplice ciclo for che effettua lattraversamento del vettore. Il vettore formato da t coppie che nel caso pessimo sono pari a (n^2-n)/2 vertici. Se la complessit parziale dellalgoritmo derivante dal ciclo for di T(t)=1+t(1+1+1+1)=4t+1=O(t). Massimizzando il risultato in funzione dei vertici n possiamo porre che t=(n^2-n)/2 da cui 2n^2-2n +1 =O(n^2). Sono state implementate tre funzioni per liberare la memoria occupata dalla lista di adiacenza, dalle matrici e dal vettore di strutture. La funzione rilascia_grafo() ha complessit proporzionale al numero di vertici da rilasciare ed al numero di archi per ogni vertice. Considerando il caso pessimo, in cui ogni vertice n collegato tramite n-1 archi a tutti gli altri vertici, allora abbiamo che T(n)= n(1+(n-1)(1+1+1)+1)=3n^2- 1=O(n^2). La funzione rilascia_matrice() ha complesit proporzionale a n, in quanto tutto il blocco di n elementi viene rilasciato n volte. Da calcolo risulta T(n)=1+n(1+1+1)+1=3n+2=O(n). La funzione rilascio_vett_strutt() rilascia il vettore di strutture ed ha complessit pari a T(t)=1+t(2+1+1)+1=4t+2=O(t), come per la funzione di stampa la funzione massimizzata nel caso in cui n=(n^2-n)/2 da cui 4(n^2-n)/2+2=2n^2-2n+2=O(n^2) Conclusioni per il calcolo della complessit generale Tenento conto nel calcolo generale di una complessit pessima in cui ognuno degli n vertici in input collegato con gli altri (n-1) vertici, in cui quindi ogni vertice possiede (n-1) archi si proceduto allottenimento del risultato per successive sommatorie dei risultati delle singole funzioni. Viste le complessit parziali delle singole funzioni, il calcolo della complessit totale del programma , come precedentemente accennato, pesata principalmente dallalgoritmo di Floyd-Warshall, che quello che determina la complessit di grado maggiore essendo asintoticamente pari a O(n^3). -
Pag. 28
Questo valore, come visibile dal calcolo, determina quindi il valore della complessit asintotica totale nel caso pessimo. Per poter calcolare un valore pi preciso di complessit nel caso pessimo, utile per poter derivare il limite superiore di tempo che lalgoritmo impiegher per risolvere lesecuzione, possiamo procedere allanalisi dei risultati parziali effettuando una sommatoria dei risultati. Nome funzione Complessit pessima relativa Controlla_aggiungi_sedi() = 6n+50 Alloca_matrice_nuovo_elemento() = 3*(3n+2) (*3 in quanto usata tre volte) Setta_matrice() = 4n^2+3n+1 Crea_matrice_da_grafo() = 3n^2-2n+2 Floyd_Warshall() = 11n^3+2n^2+2n+3 Genera_array_distanze_minime() = 4n^2+4n+7 Heapsort() = 1.5 t log t+12t-5 ( con t=(n^2-n)/2) Stampa_lista_coppie() = 2n^2-2n +1 Rilascia_matrice() = 3*(3n+2) (*3 in quanto usata tre volte) Rilascia_grafo() = 3n^2-1 Rilascia_vett_strutt() = 2n^2-2n+2 Nel main() listruzione controlla_aggiungi_sedi () viene iterata K volte con un ciclo while() che ha come condizione di uscita lultima riga letta da file. Literazione della righa K-esima deve comunque essere <=n^2 sedi differenti. Intuitivamente possiamo pensare che se gli elementi devono essere acquisiti per generare una matrice quadrata n*n allora la complessit pessima per poterlo fare deve essere proporzionale al massimo numero di elementi da acquisire, che poi non sono altro che i dati di ogni singola linea letta, quindi pari a O(n^2). Le K iterazioni che hanno una valenza pessima nel calcolo della complessit, sono solo quelle che creano vertici nuovi, ossia quelle che nella reiterazione trovano delle nuove sedi, le rimanenti iterazioni servono per linserimento di costi in un grafo gi parzialemnte definito. Quindi per il calcolo della complessit generale nel caso pessimo, possiamo procedere sommando le complessit parziali e i costi unitari restanti, riportando tutto in funzione del numero di vertici trovati: T(n)= 1+1+1+1+n*(1+(6n+50))+ 3*(3n+2)+ (4n^2+3n+1)+ (3n^2-2n+2) + (11n^3+2n^2+2n+3)+ (4n^2+4n+7)+ (1.5*(n^2-n)/2 * log (n^2-n)/2 + 12 (n^2-n)/2 5) + (2n^2-2n +1)+ 3*(3n+2)+ (3n^2-1)+ (2n^2-2n+2)+1 = 11n^3 + (1.5n^2-1.5n)/2+log(n^2-n)/2+32n^2+66n+27 =O(n^3) da cui risulta O(n^3) con n numero di vertici del grafo, pari anche al numero di righe o colonne della matrice quadrata generata.
Pag. 29