Problem to insert a graph

Asked

Viewed 677 times

1

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

The source code below has the TAD and the functions of inserting and creating graphs. Someone can find the error 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 answer

1


1. The simplest problems

First, you shouldn’t wear this:

#include <conio.h>

This is not a standard library.

In function ìnserir, you have the following:

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

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

Still in the insert function, you have a if(orientado==1) where much of the block if is equal to the block of the else. So that’s unnecessary code duplication, so you’d better take the block out of the if, keep only the block of the else and then just change that line:

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

That’s why:

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

Its function of creating graphs has a problem:

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

It happens that arrays in C go from position 0 until the tamanho - 1. Once they were allocated in the malloc, a total of V elements, then the last position is the V - 1. So the correction is this:

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

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

if(  w > G->V   )

That should be it:

if (w >= G->V)

And in the imprime_grafo_peso, that:

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

That should be it:

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

Incidentally, that while of imprime_grafo_peso would be better if you used a for.

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

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

In function inserir, you can change 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.

Do not use typedefs just to use. This tends to make the code very 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 typedefThey’re effectively just giving a different name to something else. This tends only to cause confusion, since you will have things that have two different names being that one is not a simplification of the other.

Already the first two typedefs, tend to obscure the fact that the type of data in question is a pointer. Unless you have a good reason for doing this, this kind of thing isn’t usually a good idea.

Also, you have two different list-type structures:

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 the list (along with the nodol) nowhere, so I imagine lista and the l be what you want.

By the way, you don’t seem to wear it either li and par nowhere.

The way I recommend to define yourself structs with due regard typedefs is that:

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

This form is very clean and clear, using Exemplo as a synonym for struct Exemplo. The only heartbreak is that structs containing recursive structure (such as a Exemplo up there) need to use struct Exemplo instead of just Exemplo on the inside.

It is possible to avoid the use of struct Exemplo within itself Exemplo if you use prototypes. Also, 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 used by the graph for anything, especially since 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 it. Therefore, recommend excluding the structure lista, the typedef l and the functions cria_v, incializa_lista_Q and excluir_Q.

Another thing I notice is that the 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 function parameter CriaGrafo.

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

Removing all the functions, structs and typedefs of lists and pairs that you apparently do not use, removing the typedefs unused, renaming things to have more descriptive names (example: origem and destino instead of v and w) and adding the functions to exclude, 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 remarks

I still notice a few more things:

  • Once 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 within the graph and within each vertex place the corresponding list of adjacencies. However, seeking a particular vertex within the graph would become a somewhat (but only a little) more difficult task.

  • Another thing I notice is that even if you want to have a fixed limit of vertices, since you don’t allow parallel edges or loops, then we have that the number of edges per vertex is at most equal to the number of vertices minus one. Thus, it is quite easy to eliminate the limit on the number of edges per vertex.

  • As for the problem of having to have an even number of edges, I found nothing like this. However considering that your main is empty and you do not use the infinito, PRETO, BRANCO and CINZA Still, I believe he’s incomplete or that you made a mistake somewhere that’s not in what you posted. It may also be some problem regarding accessing memory outside the correct region, since you accessed from 1 until V, instead of 0 until V - 1, although I believe this is most unlikely.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.