C - Libreria Grafo

di il
49 risposte

49 Risposte - Pagina 2

  • Re: C - Libreria Grafo

    SVNiko ha scritto:


    Non hai necessità di scrivere tante funzioni, puoi sempre utilizzare i puntatori o se vuoi, puoi utilizzare una struttura che impacca tutto, che ti farai ritornare. Ad esempio:
    
    struct valoriRitornati{
           float **pesi;
           int **matrice;
    }
    
    struct valoriRitornati convertoMatrixtoList(Grafolista G, int *V);
    Oppure
    
    void convertoMatrixtoList(Grafolista G, int *V, int ***matrice, int ***pesi);
    Allora la seconda soluzione la escluderei in partenza, in quanto tu adesso vedi una struttura con poche info, ma in realtà a mano a mano che vado ad aggiungere le funzioni che la traccia mi richiede devo aggiungere altre cose, quali la distanza, il predecessore, il tempo ecc ecc.. quindi una funzione con tutti queste variabili mi sembra eccessiva.
    Per quanto riguarda una struttura apposta con tutte variabili di ritorno, questa poi mi implica una doppia implementazione di ogni cosa, in quanto lo vado ad implementare nella struttura grafo occupando spazio di memoria, ma anche in questa struct valori di ritorno, che può contenere anche 10 informazioni. E' una cosa nuova per me, il prof. non ci hai mai mostrato qualcosa di simile(una struttura apposta per variabili di ritorno). Risulta sempre migliore come scelta rispetto ad una libreria che contenga entrambe le rappresentazioni insieme(matrici e liste)?

    Se posto la traccia dell'esercizio è meglio?!
  • Re: C - Libreria Grafo

    Dobbiamo prima chiarire il problema!

    Io ho inteso che tu voglia passare da una rappresentazione a matrice ad una rappresentazione a lista e viceversa. Il problema è questo?
  • Re: C - Libreria Grafo

    SVNiko ha scritto:


    Dobbiamo prima chiarire il problema!

    Io ho inteso che tu voglia passare da una rappresentazione a matrice ad una rappresentazione a lista e viceversa. Il problema è questo?
    Il problema è come strutturare la libreria in modo da poter fare anche questo, ma non solo.
    Inizialmente avevo creato due librerie grafolista e grafomatrice, e volevo implementare la funzione di conversione in una terza libreria grafo, ma siccome le informazioni che devono contenere i grafi sono molte, ho pensato di creare un'unica e sola libreria grafo in cui implemento le due rappresentazioni, ma tu mi hai sconsigliato. E quindi stavo cercando di capire in che modo ovviare a questa cosa. Ti riscrivo il mio attuale e funzionante codice.

    grafo.h
    #ifndef GRAFO_H_INCLUDED
    #define GRAFO_H_INCLUDED
    
    //RAPPRESENTAZIONE MATRICI DI ADIACENZE
    typedef struct grafomatrice * GrafoMatr;
    GrafoMatr creaGrafoMatr(int n);
    GrafoMatr aggiungiVerticeMatr (GrafoMatr M, char val, int i, int n);
    GrafoMatr aggiungiArcoMatr(GrafoMatr M,char curr, char val, float peso);
    int cercaVerticeMatr(char * arrayVertici, char val,int n);
    void stampaGrafoMatr (GrafoMatr M, int n);
    
    
    //RAPPRESENTAZIONE LISTE DI ADIACENZA
    typedef struct grafolista * GrafoAdj;
    typedef struct elementoLista * nodoLista;
    GrafoAdj creaGrafoLista(int n); //restituisce un puntatore ad una struttura dati grafo con n liste di adiacenza vuote
    GrafoAdj aggiungiVerticeLista (GrafoAdj g, char val, int i);
    GrafoAdj aggiungiArcoLista (GrafoAdj G, char curr, char val, float p);
    nodoLista aggiungiInLista (nodoLista lista, char val,float p);
    void stampaGrafoLista (GrafoAdj g,int n);
    void stampaLista(nodoLista lista);
    int cercaVerticeLista(GrafoAdj G, char nodo, int n);
    int verificaArcoLista(GrafoAdj G, int x, int y);
    GrafoAdj DFS_Lista (GrafoAdj G);
    GrafoAdj DFS_Visita_Lista (GrafoAdj G,nodoLista lista,int i,int n);
    
    
    //FUNZIONI DI CONVERSIONE TRA LE RAPPRESENTAZIONI
    GrafoMatr convertToMatrice (GrafoAdj G, int n);
    GrafoAdj convertToLista (GrafoMatr M, int n);
    
    #endif // GRAFO_H_INCLUDED
    
    grafo.c
    #include <stdio.h>
    #include <stdlib.h>
    #include "grafo.h"
    
    // RAPPRESENTAZIONE MATRICE DI ADIACENZA
    typedef struct grafomatrice {
    int numVertici;
    char * vertici; //array di vertici
    char * colore;
    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 creaGrafoMatr(int n)
    {
        int i,j;
        GrafoMatr M=(grafomatrice*)malloc(sizeof(grafomatrice));
        M->numVertici=n;
        M->vertici=(char*)malloc((n)*sizeof(char));
        M->colore=(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->colore[i]='b';
            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=cercaVerticeMatr(M->vertici,curr,n); //esiste sicuramente
        posVal=cercaVerticeMatr(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 cercaVerticeMatr(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 stampaGrafoMatr (GrafoMatr M, int n)
    {
        int i,j;
        printf("\n    ");
        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");
        }
    }
    
    
    // RAPPRESENTAZIONE LISTA DI ADIACENZA
    
    typedef struct elementoLista{
    char vertice;
    float peso;
    //int dist; //distanza
    struct elementoLista *next;
    }elementoLista;
    
    typedef struct grafolista {
    int numVertici;
    char * colore;
    char * pred;
    elementoLista ** nodi; //array di liste di adiacenza
    }grafolista;
    
    
    GrafoAdj creaGrafoLista(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;
                G->colore=(char*)malloc((n)*sizeof(char));
                G->pred=(char*)malloc((n)*sizeof(char));
                for(i=0;i<n;i++)
                {
                    G->nodi[i]=NULL;
                    G->colore[i]='b';
                    G->pred[i]=0;
                }
           }
       }
    
       printf("\tGRAFO CREATO!\n\n");
       return G;
    }
    
    GrafoAdj aggiungiVerticeLista (GrafoAdj G, char val, int i)
    {
        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;
    
            return G;
        }
        else
            return aggiungiVerticeLista(G,val,i+1);
    
    
    }
    
    GrafoAdj aggiungiArcoLista (GrafoAdj G, char curr, char val, float p)
    {
        int i=cercaVerticeLista(G,curr,G->numVertici); //ritorna l'indice di curr
        G->nodi[i]->next=aggiungiInLista(G->nodi[i]->next,val,p);
    
        return G;
    }
    
    nodoLista aggiungiInLista (nodoLista lista, char val, float p)
    {
        if(lista==NULL)
        {
            lista=(elementoLista*)malloc(sizeof(elementoLista));
            lista->vertice=val;
            lista->peso=p;
            lista->next=NULL;
        }
        else
            lista->next=aggiungiInLista(lista->next,val,p);
    
        return lista;
    }
    
    
    int cercaVerticeLista(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 stampaGrafoLista (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(" -> ");
                        stampaLista(g->nodi[i]->next);
                }
                else printf(" -> NULL \n");
    
    
            }
        }
    }
    
    void stampaLista(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(",");
            stampaLista(lista->next);
            }
    }
    
    
    int verificaArcoLista(GrafoAdj G,int x,int y)
    {
        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;
    }
    
    GrafoAdj DFS_Lista (GrafoAdj G)
    {
        int i;
        int n=G->numVertici;
        //inizializza grafo
        for(i=0;i<n;i++)
        {
            G->colore[i]='b';
            G->pred[i]=0;
        }
    
    
        for(i=0;i<n;i++)
        {
            if(G->colore[i]=='b')
                G=DFS_Visita_Lista(G,G->nodi[i],i,n);
        }
    
        printf("ritorno!\n");
        return G;
    }
    
     GrafoAdj DFS_Visita_Lista (GrafoAdj G,nodoLista lista,int i,int n)
     {
         G->colore[i]='g';
    
         while(lista->next!=NULL)
         {
             lista=lista->next;
             i=cercaVerticeLista(G,lista->vertice,n);
             if(G->colore[i]=='b')
             {
                 G->pred[i]=lista->vertice;
                 G=DFS_Visita_Lista(G,lista,i,n);
             }
    
    
         }
    
         G->colore[i]='n';
         return G;
     }
    
    // CONVERSIONE RAPPRESENTAZIONI
    
    GrafoMatr convertToMatrice (GrafoAdj G, int n)
    {
        int i,j;
        GrafoMatr M=NULL; nodoLista temp;
    
        M=creaGrafoMatr(n);
        for(i=0;i<n;i++)
            M->vertici[i]=G->nodi[i]->vertice;
    
        i=0;
        while(i<n)
        {
            temp=G->nodi[i]->next;
            while(temp!=NULL)
            {
                j=cercaVerticeMatr(M->vertici,temp->vertice,n);
                M->matrice[i][j]=1;
                if(abs(temp->peso>0)) M->peso[i][j]=temp->peso;
    
                temp=temp->next;
            }
            i++;
        }
    
        return M;
    
    }
    
    
    GrafoAdj convertToLista (GrafoMatr M, int n)
    {
        int i,j;
        GrafoAdj G=NULL;
    
        G=creaGrafoLista(n);
        for(i=0;i<n;i++)
        {
            G=aggiungiVerticeLista(G,M->vertici[i],i);
            for(j=0;j<n;j++)
            {
                if((i!=j)&&(M->matrice[i][j]))
                    G=aggiungiArcoLista(G,M->vertici[i],M->vertici[j],M->peso[i][j]);
            }
        }
    
        return G;
    }
  • Re: C - Libreria Grafo

    violet_prog ha scritto:


    l problema è come strutturare la libreria in modo da poter fare anche questo, ma non solo.
    Che altro dovrebbe fare?

    violet_prog ha scritto:


    Inizialmente avevo creato due librerie grafolista e grafomatrice, e volevo implementare la funzione di conversione in una terza libreria grafo, ma siccome le informazioni che devono contenere i grafi sono molte, ho pensato di creare un'unica e sola libreria grafo in cui implemento le due rappresentazioni, ma tu mi hai sconsigliato. E quindi stavo cercando di capire in che modo ovviare a questa cosa. Ti riscrivo il mio attuale e funzionante codice.
    Ti ho sconsigliato di utilizzare questo approccio perché non è molto modulare. Cioè hai fatto copia/incolla fondendo in un'unica libreria ciò che starebbe bene in due distinte librerie.

    Ti ho anche consigliato, vista la tua voglia di creare un'unica libreria, di fare un'unica struct pronta ad accogliere sia una rappresentazione a matrice, sia una rappresentazione a lista.
    
    typedef struct grafo {
        int numVertici;
        char * vertici;
        char * colore;
        float ** peso; 
        int ** matrice;
        char * pred;
        elementoLista ** nodi;
    }Grafo;
    Il punto però a mio avviso è un altro: a che cosa serve un ADT grafo? A memorizzare una serie di informazione e poter fare su di esse alcune di operazioni, visite, ecc.. Ma tutte queste cose si possono fare sia con una rappresentazione a lista adiacenze, sia con una rappresentazione a matrice delle adiacenze, che, con altri tipi di rappresentazione. Quindi il problema delle operazioni sui grafi non si pone.

    Tutt'altro è avere funzioni in grado di trasformare un grafo con una rappresentazione matriciale in una a lista e viceversa. Per ottenere questo, secondo me, puoi crearti le funzioni come ti ho consigliato proprio come seconda soluzione. Quando trasformi il grafo esso sarà rappresentato secondo il nuovo schema, quindi puoi fare su di esso tutte le operazioni che ritieni opportuno fare.
  • Re: C - Libreria Grafo

    SVNiko ha scritto:


    Per ottenere questo, secondo me, puoi crearti le funzioni come ti ho consigliato proprio come seconda soluzione. Quando trasformi il grafo esso sarà rappresentato secondo il nuovo schema, quindi puoi fare su di esso tutte le operazioni che ritieni opportuno fare.
    Intendi utilizzando delle funzioni interne alle due rispettive librerie(una per le liste e una per le matrici)?
    Quindi il prototipo della funzione di conversione avrà almeno una decina di variabili....
  • Re: C - Libreria Grafo

    violet_prog ha scritto:


    Intendi utilizzando delle funzioni interne alle due rispettive librerie(una per le liste e una per le matrici)?
    Quindi il prototipo della funzione di conversione avrà almeno una decina di variabili....
    Sì intendo quelle.
    Perché una decina di variabili, questo non riesco proprio a capirlo o evidentemente a spiegarlo.

    Se ti dessero una matrice (fatta di 1 e 0) sapresti da essa riempire un ADT grafo rappresentato come una lista? E se hai un grafo rappresentato come lista sapresti costruire una matrice (fatta di 1 e 0) che rappresenterebbe appunto la presenza o l'assenza dell'arco? Penso di si. Quindi ti basta che le funzioni di conversione ti ritornino una matrice. Adesso se hai una matrice ti costruisci le funzioni che data una matrice implementi un grafo mediante matrice e lista delle adiacenze.

    grafolista.h
    
    void estrapoloMatriceDALista(Grafolista G, int *V, int ***matrice, int ***pesi);
    void convertoMatriceINLista(Grafomatrice G, int *V, int **matrice, int **pesi);
    
    grafomatrice.h
    
    void estrapoloListaDAMatrice(Grafomatrice G, int *V, int ***matrice, int ***pesi);
    void convertoListaINMatrice(Grafolista G, int *V, int **matrice, int **pesi);
    
    Le informazioni di cui hai bisogno per costruire un grafo sono nei parametri matrice e pesi.
  • Re: C - Libreria Grafo

    Perché una decina di variabili, questo non riesco proprio a capirlo o evidentemente a spiegarlo.
    Ammesso che la mia struttura sia così
    typedef struct elementoLista{
    char vertice;
    float peso;
    int d; //tempo iniziale per dfs
    int f;//tempo finale per dfs
    struct elementoLista *next;
    }elementoLista;
    
    typedef struct grafolista {
    int numVertici;
    char * colore;
    char * pred;
    elementoLista ** nodi; //array di liste di adiacenza
    }grafolista;
    allora ho bisogno di una funzione di conversione che abbia come variabili, colore,pred,nodi,peso,d,f.... tutte le informazioni del grafo mi servono e devono conservarsi nella conversione a matrice, la cui struttura ha le stesse voci.
  • Re: C - Libreria Grafo

    Se vuoi mantenerle allora non ha scelta che copiarle in qualche modo, a questo punto la via più semplice è una struttura che impacca tutti i dati che ti servono.

    Nota: La struttura dati grafo è costituita dai dati che servono per indicare vertici, archi e pesi di questi. Tutto il resto sono dati di servizio.

    Non stai copiando la struttura dati grafo ma mantenendo anche variabili di servizio che servono per le visite, che obiettivamente non so che senso abbia conservare. (Ma se le specifiche sono quelle allora bisogna in qualche modo copiarle)
  • Re: C - Libreria Grafo

    SVNiko ha scritto:


    Non stai copiando la struttura dati grafo ma mantenendo anche variabili di servizio che servono per le visite, che obiettivamente non so che senso abbia conservare. (Ma se le specifiche sono quelle allora bisogna in qualche modo copiarle)
    Non ci avevo pensato effettivamente. Le specifiche non sono queste ma molto più generali.

    "Definire in linguaggio C una libreria per la gestidione di grafi.
    -Implementazione di grafi con le due rappresentazioni standard (tramite matrice di adiacenza; tramite liste di adicenza).
    -Prevedere la possibilità di associare pesi agli archi.
    Le operazioni da implementare nella libreria per la gestione grafi sono:
    - Lettura/Scrittura di un grafo da file
    - Conversione tra le due rappresentazioni
    - Inserimento di un nuovo vertice
    - Inserimento di un nuovo arco
    - Cancellazione di un arco o di un vertice
    - Calcolo del grafo trasposto
    - Visita in ampiezza di un grafo
    - Visita in profondità di un grafo
    - Stampa di un percorso tra due vertici (minimo e non)
    - Verifica aciclicità di un grafo"

    Ecco qua.
    Quindi posso fare una conversione che perda il resto delle informazioni...
  • Re: C - Libreria Grafo

    Dalle specifiche devi mantenere distinte le due librerie e prevedere che ci siano delle funzioni in grado di estrapolare dei dati dalla prima e inserirli nella seconda. Tutto il resto lo puoi perdere.

    Ho un solo dubbio, che non leggo nelle specifiche, cioè la storia dei pesi.
    Sei sicura che serve la mancanza di peso? Cioè non è che la dove non è specificato il peso non significa che quel peso è 1? A questo punto, il valore 0.0 significa mancanza di arco, 1.0 arco con peso uno (talvolta omesso), oppure 0.0 significa che hai due nodi che collassano uno sull'altro (bisogna obiettivamente leggere bene e comprendere le specifiche; dopotutto un grafo modella una situazione reale), tutti gli altri valori per i rispettivi pesi, negativi o positivi che siano.

    redigit: Leggendo bene le specifiche forse la libreria è una sola, cioè come ti dicevo un'unica struct che ti può mantenere sia la versione a matrice che quella a lista; quella non utilizzata ha valore NULL.
  • Re: C - Libreria Grafo

    SVNiko ha scritto:


    Ho un solo dubbio, che non leggo nelle specifiche, cioè la storia dei pesi.
    Sei sicura che serve la mancanza di peso? Cioè non è che la dove non è specificato il peso non significa che quel peso è 1? A questo punto, il valore 0.0 significa mancanza di arco, 1.0 arco con peso uno (talvolta omesso), oppure 0.0 significa che hai due nodi che collassano uno sull'altro (bisogna obiettivamente leggere bene e comprendere le specifiche; dopotutto un grafo modella una situazione reale), tutti gli altri valori per i rispettivi pesi, negativi o positivi che siano.
    la questione dei pesi la si evince dalla grammatica.

    <grafo> ::= '('<numero_nodi> ')'<adiacenze> '.'
    <adiacenze> ::= <adiacenza_nodo> { <adiacenze> }
    <adiacenza_nodo> ::= <nodo> ['->'<lista_archi> ] ';'
    <lista_archi> ::= <arco> {','<arco> }
    <arco> ::= ['('<peso> ')'] <nodo>
    <nodo> ::= identificativo
    <peso> ::= numero_reale_con_segno
    <numero_nodi> ::= numero_intero_senza_segno
  • Re: C - Libreria Grafo

    Infatti non dice che non può non esserci il valore del peso di un arco
  • Re: C - Libreria Grafo

    SVNiko ha scritto:


    Infatti non dice che non può non esserci il valore del peso di un arco
    ['('<peso> ')']
    le parentesi quadre indicano un opzione
  • Re: C - Libreria Grafo

    Per curiosità hai un esempio del file? Puoi copiare un frammento?
  • Re: C - Libreria Grafo

    (6)A->(-2.5)B;B->C,(+4.2)D;C->(+3.2)D,F;D;E->(+1.0)A;F;.
Devi accedere o registrarti per scrivere nel forum
49 risposte