Ciao a tutti. Sto svolgendo un progetto didattico per la creazione di una libreria che gestisca un grafo. La traccia prevede una serie di funzionalità, tra cui la creazione del grafo a partire dal parsing di un file di testo secondo una codifica data. Tralasciando questo passaggio e la libreria che ho implementato per fare ciò, quel che mi preme è capire bene qual è il modo più efficiente per gestire l'implementazione delle strutture dati (liste di adiacenza e matrici di adiacenza).
La mia idea di partenza (e quella che ho al momento implementato) è la divisione di due librerie, una grafomatrice.h (e grafomatrice.c) in cui gestisco le matrici di adiacenza e le funzionalità annesse, un altra libreria grafolista.h (e grafolista.c) in cui gestisco quel che riguarda le liste di adiacenza. Il problema mi sorge nel momento in cui devo creare delle funzioni che permettano la conversione da una rappresentazione all'altra, in quanto mi tocca creare una nuova libreria ad esempio grafo.h. Ora il mio dubbio è.. Mi conviene creare una terza libreria che veda entrambe le rappresentazioni, o piuttosto creare un'unica e sola libreria grafo.h che contenga entrambe le rappresentazioni e quindi anche le funzioni di conversione? Allego il mio codice, su cui ho comunque dei dubbi(soprattutto per la struttura dati che rappresenta le matrici)
main.c (è chiaramente parziale)
#include <stdio.h>
#include <stdlib.h>
#include "grafolista.h"
#include "grafomatrice.h"
#include "grafoparser.h"
#include "grafo.h"
int menuIniziale(void);
int menuGrafo(void);
char * scegliFile(void);
char * scriviGrafo(void);
int main()
{
FILE *file;
char *nome;
GrafoAdj G=NULL;
GrafoMatr M=0;
int numVertici=0;
int scelta,tipo,conv;
printf("\t***************************************************\n");
printf("\t* *\n");
printf("\t* PROGRAMMA PER LA GESTIONE DI GRAFI *\n");
printf("\t* *\n");
printf("\t***************************************************\n\n\n");
printf("Benvenuto nel programma di gestione della struttura dati dinamica: GRAFO\n");
printf("Prima di iniziare e' necessario costruire ALMENO un Grafo.\n\n");
system("PAUSE");
scelta= menuIniziale();
if (scelta==1) nome = scegliFile();
else nome= scriviGrafo();
file = fopen(nome,"r");
printf("\n>>Scegli il tipo di rappresentazione:\n1)Liste di adiacenza\n2)Matrice di adiacenza\n\n");
scanf("%d",&tipo);
printf("\n\nINIZIO TRADUZIONE FILE...\n");
system("PAUSE"); system("cls");
printf("Le informazioni estratte sono le seguenti:\n\n");
if(tipo==1) numVertici=parseGrafo(file,&G,0,tipo); // Parse grafo
else if(tipo==2) numVertici=parseGrafo(file,NULL,&M,tipo);
fclose(file);
printf("\nIl grafo creato:\n");
if(G!=NULL) grafo_stampa(G,numVertici);
else if (M!=NULL) stampaMatr(M,numVertici);
else
printf("Grafo vuoto\n");
system("PAUSE");
system("cls");
printf("Converti da un tipo ad un altro:\n1)Da Lista a Matrice\n2)Da Matrice a Lista\n");
scanf("%d",&conv);
if(conv==1)
{
//CONVERTI DA LISTA A MATRICE
}
else
{
//CONVERTI DA MATRICE A LISTA
}
system("PAUSE");
// DOPO AGGIUNGO QUESTA FUNZIONE scelta=menuGrafo();
return 0;
}
int menuIniziale(void)
{
int x;
system("cls");
printf("\t CREAZIONE GRAFO :\n\n");
printf("1)Leggi il grafo da un file;\n2)Scrivi un nuovo grafo su un file.\n");
scanf("%d",&x);
return x;
}
char *scegliFile(void)
{
char *nome; int x,y;
printf("\n\nScegli uno dei file esistenti:\n1) Grafo 1\n2) Grafo 2\n3) Grafo 3\n");
scanf("%d",&x);printf("\n");
switch(x)
{
case 1:
nome="grafo1.txt";
break;
case 2:
nome="grafo2.txt";
break;
case 3:
nome="grafo3.txt";
break;
default:
printf("::ERRORE:: La scelta non è valida!!\n\n Riprova -> 1\nPremi un tasto qualsiasi per Uscire...\n");
scanf("%d",&y);
if(y==1) nome=scegliFile();
else exit(1);
}
return nome;
}
char * scriviGrafo()
{
system("cls");
int n,x,y,j,v,i;
char *nome="grafonew.txt";
FILE *filenuovo=fopen("grafonew.txt","w");
printf("\t\t.:POPOLAMENTO GRAFO:.\n\n");
printf("Quanti vertici deve contenere il grafo? ");
scanf("%d",&n); printf("\n");
fprintf(filenuovo,"%c%d%c",'(',n,')');
for(i=1;i<=n;i++)
{
printf("\nVertice %d :\n",i);
fprintf(filenuovo,"%c%d%s",' ',i,"->");
printf("\n1)Crea Archi\n2)Passa al vertice successivo\n");
scanf("%d",&x);
if(x==2) fprintf(filenuovo,"%s","(-0.0);");
else
{
printf("Quanti archi? ");
scanf("%d",&y);printf("\n");
fprintf(filenuovo,"%s%d%s","(+",y,".0)");
printf("Inserisci vertici incidenti \n");
for(j=1;j<=y;j++)
{
scanf("%d",&v);
fprintf(filenuovo,"%c%d%c%d",' ',i,'|',v);
if(j==y) fprintf(filenuovo,"%c ",';');
}
}
}
fprintf(filenuovo,"%c",'.');
printf("FILE SCRITTO CON SUCCESSO!!!\n");
fclose(filenuovo);
system("PAUSE");
return nome;
}
int menuGrafo(void)
{
int scelta;
printf("\t\t.:: MENU GRAFO ::.\n\n");
printf("1- Inserisci Vertice\n2- Inserisci Arco\n");
printf("3- Cancella Vertice\n4- Cancella Arco\n");
printf("5- Calcola Grafo Trasposto\n6- Visita in Ampiezza\n7- Visita in Profondità\n");
printf("8- Stampa di un percorso tra due vertci\n9- Verifica Aciclicità del Grafo\n");
printf("10- Cambia rappresentazione grafo.\n\n");
scanf("%d",&scelta);
switch (scelta)
{
case 1:break;
case 2:break;
case 3:break;
case 4:break;
case 5:break;
case 6:break;
case 7:break;
case 8:break;
case 9:break;
case 10:break;
}
return scelta;
}
grafoparser.h
#ifndef GRAFOPARSER_H_INCLUDED
#define GRAFOPARSER_H_INCLUDED
typedef enum {PARSX, PARDX, NUM, PUNTO, MENO, PIU, PUNT, PUNTOV, VIRG, PESO, ID} type; // Tipo dei simboli terminali
int parseGrafo (FILE *file, GrafoAdj *G, GrafoMatr *M, int tipo);
void verticiAdj (GrafoAdj G, GrafoMatr M, char nodo, FILE *file);
int confronto(FILE *file, type x);
void sposta (FILE *file, type x);
int traduciNumeroNodi(FILE *file);
int traduciIntero(FILE *file);
float traduciPeso (FILE *file);
#endif // GRAFOPARSER_H_INCLUDED
grafolista.h
#ifndef GRAFOLISTA_H_INCLUDED
#define GRAFOLISTA_H_INCLUDED
typedef struct grafolista * GrafoAdj;
typedef struct elementoLista * nodoLista;
GrafoAdj creaGrafo(int n); //restituisce un puntatore ad una struttura dati grafo con n liste di adiacenza vuote
GrafoAdj aggiungiVertice (GrafoAdj g, char val, int i);
GrafoAdj aggiungiArco (GrafoAdj G, char curr, char val, float p);
nodoLista aggiungiInLista (nodoLista lista, char val,float p);
void grafo_stampa (GrafoAdj g,int n);
void lista_stampa(nodoLista lista);
int cercaVertice(GrafoAdj G, char nodo, int n);
int verificaArco(GrafoAdj G, int x, int y);
//int verificaAdiacenze(nodoLista lista, char y);
#endif // GRAFOLISTA_H_INCLUDED
grafolista.c
#include <stdio.h>
#include <stdlib.h>
#include "grafolista.h"
#include <stdbool.h>
typedef struct elementoLista{
char vertice;
float peso;
//char pred; //predecessore
//int dist; //distsnza
struct elementoLista *next;
}elementoLista;
typedef struct grafolista {
int numVertici;
elementoLista ** nodi; //array di liste di adiacenza
}grafolista;
char *colore;
GrafoAdj creaGrafo(int n)
{
GrafoAdj G; int i;
G=(grafolista*)malloc(sizeof(grafolista));
if(G==NULL)printf("Errore allocazione grafo!\n");
else
{
G->nodi=(elementoLista**)malloc(n*sizeof(elementoLista*)); //alloca l'array di liste
if((G->nodi==NULL)&&(n>0))
{
printf("Errore allocazione archi!\n");
free(G);
G=NULL;
}
else
{
G->numVertici=n;
colore=(char*)malloc(n*sizeof(char));
for(i=0;i<n;i++)
{
G->nodi[i]=NULL;
colore[i]='b';
}
}
}
printf("\tGRAFO CREATO!\n\n");
return G;
}
GrafoAdj aggiungiVertice (GrafoAdj G, char val, int i)
{
printf("Sono in aggiungi vertice, con i=%d e val=%c\n",i,val);
if(G->nodi[i]==NULL)
{
G->nodi[i]=(elementoLista*)malloc(sizeof(elementoLista));
G->nodi[i]->vertice=val;
G->nodi[i]->peso=0.0;
G->nodi[i]->next=NULL;
printf("\tAggiunto vertice %c in posizione %d\n",val,i);
return G;
}
else
return aggiungiVertice(G,val,i+1);
}
GrafoAdj aggiungiArco (GrafoAdj G, char curr, char val, float p)
{
printf("Sono in aggiungiArco con curr=%c e nodo da inserire=%c\n",curr,val);
int i=cercaVertice(G,curr,G->numVertici); //ritorna l'indice di curr
printf("NODO CORRENTE G->nodi[%d]= %c\n",i,G->nodi[i]->vertice);
G->nodi[i]->next=aggiungiInLista(G->nodi[i]->next,val,p);
printf("\tAGGIUNTO ARCO DA %c A %c\n",curr,val);
return G;
}
nodoLista aggiungiInLista (nodoLista lista, char val, float p)
{
if(lista==NULL)
{
lista=(elementoLista*)malloc(sizeof(elementoLista));
lista->vertice=val;
lista->peso=p; printf("Inserito peso= %.2f\n",lista->peso);
lista->next=NULL;
}
else
lista->next=aggiungiInLista(lista->next,val,p);
return lista;
}
int cercaVertice(GrafoAdj G, char nodo, int n)
{
int i=0;
while((i<n)&&(G->nodi[i]!=NULL))
{
if(G->nodi[i]->vertice==nodo)
return i;
i++;
}
return 0;
}
void grafo_stampa (GrafoAdj g, int n)
{
int i;
if (g==NULL) { printf("\n"); return;}
else
{
for(i=0;i<n;i++)
{
printf("%c ",g->nodi[i]->vertice);
if(g->nodi[i]->next!=NULL)
{
printf(" -> ");
lista_stampa(g->nodi[i]->next);
}
else printf(" -> NULL \n");
}
}
}
void lista_stampa(nodoLista lista) {
if (lista == NULL) {printf("\n"); return;}
else
{
if(abs(lista->peso) > 0) printf("(%.2f)",lista->peso);
printf("%c",lista->vertice);
if(lista->next!=NULL) printf(",");
lista_stampa(lista->next);
}
}
int verificaArco(GrafoAdj G,int x,int y)
{
printf("x=%d y=%d\n",x,y);
int arco;
nodoLista DA=G->nodi[x]->next;
char A=G->nodi[y]->vertice;
while(DA!=NULL)
{
if(DA->vertice==A)
return 1;
else
DA=DA->next;
}
return 0;
}
grafomatrice.h
//grafomatrice.h
#ifndef GRAFOMATRICE_H_INCLUDED
#define GRAFOMATRICE_H_INCLUDED
typedef struct grafomatrice * GrafoMatr;
GrafoMatr creaMatrice(int n);
GrafoMatr aggiungiVerticeMatr (GrafoMatr M, char val, int i, int n);
GrafoMatr aggiungiArcoMatr(GrafoMatr M,char curr, char val, float peso);
int cercaVerticeMatrice(char * arrayVertici, char val,int n);
void stampaMatr (GrafoMatr M, int n);
#endif // GRAFOMATRICE_H_INCLUDED
grafomatrice.c
#include <stdio.h>
#include <stdlib.h>
#include "grafomatrice.h"
typedef struct grafomatrice {
int numVertici;
char * vertici; //array di vertici
float ** peso; //matrice dei pesi //i pesi non posso metterli al posto dell'1 nella matr adj in quanto nn so come rapp un arco senza peso!
int ** matrice;
}grafomatrice;
GrafoMatr creaMatrice(int n)
{
int i,j;
GrafoMatr M=(grafomatrice*)malloc(sizeof(grafomatrice));
M->numVertici=n;
M->vertici=(char*)malloc((n)*sizeof(char));
M->peso=(float**)malloc((n)*sizeof(float*));
M->matrice=(int**)malloc((n)*sizeof(int*));
for(i=0;i<n;i++)
{
M->vertici[i]=0;
M->peso[i]=(float*)malloc((n)*sizeof(float));
M->matrice[i]=(int*)malloc((n)*sizeof(int));
for(j=0;j<n;j++) M->matrice[i][j]=0;
}
return M;
}
GrafoMatr aggiungiVerticeMatr (GrafoMatr M, char val, int i, int n)
{
if((i<n)&&(M->vertici[i]!=val))
{
if(M->vertici[i]==0)
M->vertici[i]=val;
else
return aggiungiVerticeMatr(M,val,i+1,n);
}
return M;
}
GrafoMatr aggiungiArcoMatr(GrafoMatr M,char curr, char val, float peso)
{
int posCurr,posVal;
int n=M->numVertici;
posCurr=cercaVerticeMatrice(M->vertici,curr,n); //esiste sicuramente
posVal=cercaVerticeMatrice(M->vertici,val,n); //potrebbe non esser stato inserito
if(M->vertici[posVal]==0)
M=aggiungiVerticeMatr(M,val,0,n);
M->matrice[posCurr][posVal]=1;
M->peso[posCurr][posVal]=peso;
return M;
}
int cercaVerticeMatrice(char * arrayVertici, char val,int n)
{
int i=0;
while(i<n)
{
if((arrayVertici[i]==val) || (arrayVertici[i]==0))//se arriva ad una casella vuota vuol dire che non ha trovato altro;
return i;
else i++;
}
return 0;
}
void stampaMatr (GrafoMatr M, int n)
{
int i,j;
printf(" ");
for(i=0;i<n;i++) printf("%c ",M->vertici[i]);
printf("\n\n");
for(i=0;i<n;i++)
{
printf(" %c ",M->vertici[i]);
for(j=0;j<n;j++)
{
//if(abs(M->peso[i][j]) > 0) printf("(%.2f)",M->peso[i][j]);
printf("%d ",M->matrice[i][j]);
}
printf("\n");
}
}
grafo.h
#ifndef GRAFO_H_INCLUDED
#define GRAFO_H_INCLUDED
GrafoMatr convertToMatrice (GrafoAdj G, GrafoMatr M, int n);
GrafoAdj convertToLista (GrafoAdj G, GrafoMatr M, int n);
#endif // GRAFO_H_INCLUDED
grafoparser.c non l'ho scritto in quanto non avendo precisato la grammatica stabilita, mi sembrava inutile. Ed inoltre perchè il programma compila ed esegue, il mio interesse è un consiglio sulle strutture dati e appunto la divisione di esse nelle varie librerie.
Grazie per l'attenzione.