Problem to insert a graph

I'm trying to insert vertices and bindings into a graph, but it only works when the graph has even number of edges.

The source code below has the TAD and the functions of inserting and creating graphs. Can anyone find the mistake for me?

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define infinito 10000
#define BRANCO 0
#define CINZA 1
#define PRETO 2

typedef struct grafo *Grafo;
typedef struct nodo *link;
typedef struct list nodol;
typedef struct li par;
typedef struct l lista;

void limpar_tela()
{
    //system("cls");
//  printf("\033[2J"); /* limpa a tela */
//  printf("\033[1H"); /* poe o curso no topo */
}


//a lista de adjacência de um vertice que aponta para várias arestas ligantes atravez desta lista do itpo nodo
//onde temo nosso v->w, em que w é o vertice de destino de um vertice V, que é seguida por um link de de apontadores para arestas

struct l
{
    int v;
    lista *proximo;
};



//a lista de adjacência de um vertice que aponta para várias arestas ligantes atravez desta lista do itpo nodo
//onde temo nosso v->w, em que w é o vertice de destino de um vertice V, que é seguida por um link de de apontadores para arestas


struct nodo
{
    int w,peso;
    link proximo;
};

struct li
{
    int peso,a;
};

struct list
{
    int v,w,peso;
    nodol *proximo;
};







//A função novo nodo, como nome diz aparti de um w criamos um link na lista de adj do vertice de origem v
// criamos o novo novo, alocamos e colocando os conteudo W neste e retornamos o próprio nodo para linkar a lista
link Novonodo( int w, link proximo)
{

    link a = malloc( sizeof (struct nodo));
    a->w = w;
    a->proximo = proximo;
    return a;
}



// a struct grafo, representa a repsentação do Grafo por lista de ajdacência, onde que adj é um ponteiro para um vetor
// de lista de adjacência, a V numero de vertices e A número de arestas.
struct grafo
{
    int V;
    int A;
    link *adj;
};

//Aqui criamos um grafo com a quantidade de arestas e vertices informado pelo usuário sem esquecer a restriçao do problema
// criamos uma lista de vertices, que todo seus apontadores são para NULL;

Grafo CriaGrafo( int V, int a)
{
    int x;
    Grafo G = malloc( sizeof *G);
    G->V = V;
    G->A = a;
    G->adj = malloc( V * sizeof (link));
    for (x = 1; x <=V; x++)
        G->adj[x] = NULL;
    return G;
}


///Na função inserir adiciona um link (entre v->w) entrem a origem e destino onde que a variavel QTDA=Quantide de arestas
// primeiro IF vericamos se não ira ligar em um vertice não existente
// depois enquando fazemos a contagem verificamos se existe aresta paralela ou se ira fazer um laço no no grafo caso seja orientado
//no final verificamos se não excedemos a capacidade permitida de inserção de aresta

void inserir(int orientado, Grafo G, int v, int w, int peso)
{
    link a;
    int qtda=0;


    if(orientado==1)
    {



        if ( v==w )
        {

            printf("Nao e possivel adicionar laço\n");
            return;

        }


        if(  w > G->V   )
        {
            printf("Nao e possivel adicionar, este verticce nao existe\n");
            return;
        }


        //conto quantas arestas ja foram adicionadas e verifico se existe aresta paralela e também laço
        for (a = G->adj[v]; a != NULL; a = a->proximo)
        {
            qtda=qtda+1;

            if ( v==w || a->w == v )
            {

                printf("Nao e possivel adicionar aresta paralela\n");
                return;

            }


        }




        //verifico se ira adicionar uma aresta desde que não exceda a quantidade limite estabelecida
        if( G->A > qtda)
        {
            printf("v = %d\n",v);
            G->adj[v] = Novonodo( w, G->adj[v]);

        }
        else printf("Nao e possivel adicionar mais arestas ao vertice|%d|\n", v);

    }
    else
    {
        printf("passou\n");
        //verifico se ira adicionar um laço
        if ( v==w )
        {
            printf("Nao e possivel adicionar laco\n");
            return;
        }


        if(  w > G->V   )
        {
            printf("Nao e possivel adicionar, este verticce nao existe\n");
            return;
        }


        //conto quantas arestas ja foram adicionadas
        for (a = G->adj[v]; a != NULL; a = a->proximo)
        {
            qtda=qtda+1;

            if(a->w==w)
            {
                printf("Nao sera possivel adicionar aresta paralela\n" );
                return;
            }

        }

        //verifico se ira adicionar uma aresta desde que não exceda a quantidade limite estabelecida
        if( G->A > qtda)
        {

            //caso o grafo não seja orientado se eu tendo |v|->[w], terei também de |w|->[v]

            G->adj[v] = Novonodo( w, G->adj[v]);
            G->adj[w] = Novonodo( v, G->adj[w]);


        }
        else printf("Nao e possivel adicionar mais arestas ao vertice|%d|\n", v);


    }
}




//Imprime o grafo  como uma lista de adjacencia
void imprime_grafo_peso(Grafo g)
{

    link a;

    int i=1;
    while(i<=g->V)
    {
        printf("|%d|-",i);

        for(a=g->adj[i]; a!=NULL; a=a->proximo) printf("[%d,p%d]->", a->w,a->peso);


        printf("0\n");
        i++;
    }

    printf("\n");
}


//Crio um nodo do tipo lista para vertices
lista *cria_v(lista *proximo, int v)
{

    lista *novo = malloc( sizeof (lista));
    novo->v=v;
    novo->proximo = proximo;

    return novo;
}


//inicializo a minha lista de com os vertices percentes ao meu grafo
void incializa_lista_Q(lista **q, Grafo g)
{
    *q=NULL;
    int i=1;
    while(i<= g->V)
    {
        *q=cria_v(*q,i);
        i++;
    }
}

///pego um da lista Q e um V dentro dela faço as seguintes verificações

lista* excluir_Q(lista *q, int v)
{
    lista *ant, *atual;
    ant=NULL;
    atual=q;


//verifico  até chegar o final da minha lista de Vertices ou encontrar o elemento a ser excluido
    while(atual!=NULL && atual->v!=v)
    {
        ant=atual;
        atual=atual->proximo;

    }
    //caso não encontro meu elemento retorno o própria lista
    if(atual == NULL) return q;
    //caso o anterior seja null, então apenas precisamos apontar para o próximo elemento da lista
    if(ant==NULL) q=atual->proximo;
//caso contrário existe um elemento no meio atualizo os ponteiros da nova lista
    else ant->proximo = atual->proximo;
//exclui meu vertice atual ou seja desaloca o nó não mais necessário na minha lista
    free(atual);

//retorno minha nova lista de elementos
    return q;



}

int main(){

}
 1
Author: Victor Stafusa, 2017-01-22

1 answers

1. The simplest problems

First, you should not use this:

#include <conio.h>

This is not a standard library.

In the function ìnserir, you have the following:

if ( v==w || a->w == v )

However the v==w has already been checked above, where there is a return if this is true. Therefore, this underexpression will always be false, and therefore can be eliminated.

Still in the Insert Function, you have a if(orientado==1) where much of the block of if is equal to the block of else. This hence is unnecessary code duplication, so you'd be much better off taking the block from if, keeping only the block from else and then swapping only that line:

G->adj[w] = Novonodo( v, G->adj[w]);

So:

if (orientado) G->adj[w] = Novonodo(v, G->adj[w]);

Your graph creation function has a problem:

G->adj = malloc( V * sizeof (link));
for (x = 1; x <=V; x++)
    G->adj[x] = NULL;

It occurs that arrays in C range from position 0 to tamanho - 1. Once a total of V elements have been allocated in malloc, then the last position is V - 1. Hence the correction that's it:

G->adj = malloc(V * sizeof(link));
for (x = 0; x < V; x++) {
    G->adj[x] = NULL;
}

This also means that in the function inserir, this from here:

if(  w > G->V   )

Should be this:

if (w >= G->V)

And in imprime_grafo_peso, this:

int i=1;
while(i<=g->V)

Should be this:

int i = 0;
while (i < g->V)

Incidentally, this while from imprime_grafo_peso would look better if you used a for.

The same as in while of imprime_grafo_peso also applies to incializa_lista_Q.

In the nodo structure, you have the fields w and peso, but you are only using w. You even read the peso in imprime_grafo_peso and prints it, but never sets this weight anywhere. Note that you do not use the peso parameter of the inserir function. Therefore, the function Novonodo should also receive the weight of the node.

In the function inserir, you can exchange the qtda=qtda+1 for qtda++.

2. Deeper structural changes

After making the changes I recommended above, there are a few more possible changes, but they are structural and deeper changes.

No use typedefs only for use. This tends to make the code pretty confusing. You use 5 typedefs in your code:

typedef struct grafo *Grafo;
typedef struct nodo *link;
typedef struct list nodol;
typedef struct li par;
typedef struct l lista;

The last three typedefS are effectively just giving a different name to something else. This only tends to cause confusion, since you will have things that have two different names being that one is not a simplification of the other.

The first two typedefs tend to obscure the fact that the data type in question is a pointer. To unless you have a good justification for doing this, this kind of thing is usually not a good idea.

Also, you have two different structures of type list:

struct l
{
    int v;
    lista *proximo;
};

struct list
{
    int v,w,peso;
    nodol *proximo;
};

Remembering that lista is another name for l and that nodol is another name for list. However, you don't seem to be using list (along with nodol) anywhere, so I imagine that lista and l is what you want.

By the way, you look also do not look use li and par nowhere.

The way I recommend to define struct s with the proper typedef s is this:

typedef struct Exemplo {
    int a, b, c;
    float d;
    OutroStruct *e;
    struct Exemplo *f;
} Exemplo;

This form is quite clean and clear, using Exemplo as a synonym for struct Exemplo. The only downside is that struct s that contain recursive structure (like the Exemplo above) need to use struct Exemplo instead of just Exemplo from the inside.

You can avoid using struct Exemplo within Exemplo itself if you use prototypes. In addition, in the case of indirectly recursive structures, using prototypes is the best solution. For example:

typedef struct Recursivo Recursivo;
typedef struct Recursivo {
    char i, j, k;
    Recursivo *m;
} Recursivo;

typedef struct Homem Homem;
typedef struct Mulher Mulher;

typedef struct Homem {
    int a, b, c;
    Mulher *esposa;
} Homem;

typedef struct Mulher {
    double x, y, z;
    Homem *marido;
} Mulher;

Its structure lista (also called l) does not seem to be being used by the graph for anything, even more so because the graph already has a list of adjacencies represented by link and nodo and the functions CriaGrafo, inserir and imprime_grafo_peso know how to take care of her. Therefore, I recommend deleting the structure lista, the typedef l and functions cria_v, incializa_lista_Q e excluir_Q.

Another thing I notice is that orientado is a characteristic of the graph, and not of the edge to be inserted. Therefore, this should be within the structure grafo and be a parameter of the function CriaGrafo.

You have functions to create nodes and graphs, but you don't have the functions to delete. it is important to create these functions as well.

Removing all functions, structs and typedefs from lists and pairs that you apparently don't use, removing the typedefs not used by renaming things to have more descriptive names (example: origem and destino instead of v and w) and adding the functions to delete, your code looks like this:

#include <stdio.h>
#include <stdlib.h>
#define infinito 10000
#define BRANCO 0
#define CINZA 1
#define PRETO 2

void limpar_tela() {
    //system("cls");
    //printf("\033[2J"); /* limpa a tela */
    //printf("\033[1H"); /* põe o cursor no topo */
}

typedef struct Nodo {
    int peso, destino;
    struct Nodo *proximo;
} Nodo;

typedef struct Grafo {
    int maximo_vertices, maximo_arestas_por_vertice, orientado;
    Nodo **adjacencias;
} Grafo;

Nodo *Nodo_novo(int destino, int peso, Nodo *proximo) {
    Nodo *a = malloc(sizeof(Nodo));
    a->peso = peso;
    a->destino = destino;
    a->proximo = proximo;
    return a;
}

void Nodo_destroi(Nodo *nodo) {
    Nodo *atual = nodo;
    while (atual != NULL) {
        Nodo *aux = atual->proximo;
        free(atual);
        atual = aux;
    } 
}

Grafo *Grafo_novo(int orientado, int maximo_vertices, int maximo_arestas_por_vertice) {
    int x;
    Grafo *g = malloc(sizeof(Grafo));
    g->orientado = orientado;
    g->maximo_vertices = maximo_vertices;
    g->maximo_arestas_por_vertice = maximo_arestas_por_vertice;
    g->adjacencias = malloc(maximo_vertices * sizeof(Nodo *));
    for (x = 0; x < maximo_vertices; x++) {
        g->adjacencias[x] = NULL;
    }
    return g;
}

void Grafo_destroi(Grafo *g) {
    int x;
    for (x = 0; x < g->maximo_vertices; x++) {
        Nodo_destroi(g->adjacencias[x]);
    }
    free(g->adjacencias);
    free(g);
}

void Grafo_inserir_aresta(Grafo *g, int origem, int destino, int peso) {
    Nodo *a;
    int qtda = 0;

    if (origem == destino) {
        printf("Nao e possivel adicionar laço\n");
        return;
    }

    if (destino > g->maximo_vertices) {
        printf("Nao e possivel adicionar, este vertice nao existe.\n");
        return;
    }

    for (a = g->adjacencias[origem]; a != NULL; a = a->proximo) {
        qtda++;

        if (a->peso == destino) {
            printf("Nao sera possivel adicionar aresta paralela.\n");
            return;
        }
    }

    if (qtda > g->maximo_arestas_por_vertice) {
        printf("Nao e possivel adicionar mais arestas ao vertice %d.\n", origem);
        return;
    }

    g->adjacencias[origem] = Nodo_novo(destino, peso, g->adjacencias[origem]);
    if (g->orientado) g->adjacencias[destino] = Nodo_novo(origem, peso, g->adjacencias[destino]);
}

void Grafo_imprime(Grafo *g) {
    Nodo *a;
    int i;

    for (i = 0; i < g->maximo_vertices; i++) {
        printf("|%d|-", i);

        for (a = g->adjacencias[i]; a != NULL; a = a->proximo) {
            printf("[%d,p%d]%s", a->destino, a->peso);
        }

        printf("0\n");
    }

    printf("\n");
}

int main() {

}

3. Final considerations

I still notice a few more things:

  • Since you already work with chained lists, you can get rid of having a limit on the number of vertices in the graph. The idea would be to keep a list of vertices inside the graph and inside from each vertex put the corresponding list of adjacencies. However, finding a certain Vertex within the graph would become a somewhat (but only slightly) more difficult task.

  • Another thing I notice is that even if you want to have a fixed limit of vertices, since you do not allow parallel edges and no loops, then we have that the number of edges per Vertex is at most equal to the number of vertices minus one. Therefore, it is quite easy to eliminate the limit the number of edges per Vertex.

  • As for the problem of having to have an even number of edges, I didn't find anything like that. However considering that your main is empty and that you do not use the infinito, PRETO, BRANCO and CINZA still, I believe it is incomplete or that you made a mistake somewhere that is not in what you posted. There may also be some problem regarding accessing memory outside the correct region, since you accessed from 1 until V, rather than 0 until V - 1, although I believe this is more unlikely.

 1
Author: Victor Stafusa, 2017-01-22 20:20:41