Search code examples
c++algorithmquicksortminimum-spanning-treekruskals-algorithm

C++ implementation of Kruskal's algorithm


I'm trying to implement Kruskal's algorithm. Here is a map of the structures I'm using:

g = array of edges, it keeps the left end and the right end and the edge's weight;

c = array which memorises the conex components; c[N] = the conex component in which we find the Nth vertex;

a = array which memorises the MST;

m = nr of vertexes;

n = nr of nodes.

There are two problems with the following code:

1) For the following input it outputs that the cost of the MST is 18 (which is wrong, the cost is actually 14):

7 ( =m )

6 ( =n )

1 2 9

1 3 5

1 4 2

2 3 7

3 5 3

4 6 1

5 6 1

2) Compiling the code step by step doesn't give any errors, although the actual execution of the program halts at some point, I figure it's when printing the cost of the MST.

Thanks for helping! Here's the code:

#include<stdio.h>
#include<stdlib.h>
#define grafMAX 101

FILE *fin = fopen("grafin.txt","r");
FILE *fout = fopen("grafout.txt","w");

struct Vertex{
    int first,last,Cost;
};

void read_graf(Vertex **g, int *c, int &m, int &n){
    int x,y,w;
    fscanf(fin,"%d%d",&m,&n);
    *g = (Vertex *)malloc(m*sizeof(Vertex));
    for(int i=1;i<=m;++i){
        fscanf(fin,"%d%d%d",&x,&y,&w);
        (*g+i)->first = x;
        (*g+i)->last = y;
        (*g+i)->Cost = w;
    }
    for(int i=1;i<=n;++i)
        c[i] = i;
}

int costMST(Vertex *g, int *a, int n){
    int MST = 0;
    for(int i=1;i<n;++i)
        MST += g[a[i]].Cost;
    return MST;
}

void Kruskal(Vertex *g, int *c, int *a, int n){
    int nr = 0, mini, maxi;
    for(int i=1;nr<n-1;++i)
        if(c[g[i].first] != c[g[i].last]){
            a[++nr] = i;
            if(c[g[i].first] < c[g[i].last]){
                mini = c[g[i].first];
                maxi = c[g[i].last];
            }
            else{
                maxi = c[g[i].first];
                mini = c[g[i].last];
            }
            for(int j=1;j<=n;++j)
                if(c[j] == maxi)
                    c[j] = mini;
        }
}

inline int cmp(const void *a, const void *b){
    return (((Vertex *)a)->Cost - ((Vertex *)b)->Cost);
}

int a[grafMAX], c[grafMAX];

int main(){
    Vertex *g;
    int m, n;
    read_graf(&g,c,m,n);
    qsort(g,m,sizeof(Vertex),cmp);
    Kruskal(g,c,a,n);
    fprintf(fout,"The cost of the MST is: %d.\n",costMST(g,a,n));
    fclose(fin);
    fclose(fout);
    return 0;
}

Solution

  • There are a lot of off by one errors in your code, I think because you are numbering your vertices from 1 rather than 0. One of these errors was causing it to crash, and I think another one was causing the wrong result to be produced.

    I changed all of the internal numbering to be 0-based and and that has got it to work. I renamed your variables because they were quite preposterously named (what you call a Vertex is an Edge) and I couldn't make sense of the code with them like that.

    I'm afraid I lost track of everything I changed, but I expect you can see what I did if you compare it with your original code.

    Notice that I added some debug lines. When you can't work out what your code is doing, just print the relevant variables and you will soon see what the problem is.

    #include<stdio.h>
    #include<stdlib.h>
    #define grafMAX 101
    
    FILE *fin = fopen("grafin.txt","r");
    FILE *fout = fopen("grafout.txt","w");
    
    struct Edge {
        int first,last,Cost;
    };
    
    void read_graf(Edge **g, int *components, int &num_edges, int &num_vertices){
        int x,y,w;
        fscanf(fin,"%d %d",&num_edges,&num_vertices);
        *g = (Edge *)malloc(num_edges*sizeof(Edge));
        for(int i=0;i<num_edges;++i){
            fscanf(fin,"%d %d %d",&x,&y,&w);
            (*g+i)->first = x - 1;
            (*g+i)->last = y - 1;
            (*g+i)->Cost = w;
        }
        for(int i=0;i< num_vertices;++i)
            components[i] = i;
    }
    
    int costMST(Edge *edges, int *answer, int num_edges){
        int MST = 0;
        for(int i=0;i<num_edges;++i)
            MST += edges[answer[i]].Cost;
        return MST;
    }
    
    void print_components(const int* components, int num_components) 
    {
        for (int i = 0; i < num_components; i++) {
            printf("Vertex %d is in component %d\n", i, components[i]);
        }
        putchar('\n');
    }
    
    void print_edge(const Edge& edge, int index)
    {
        printf("Edge %d connecting %d to %d with weight %d", index, edge.first, edge.last, edge.Cost);
    }
    
    void Kruskal(Edge *edges, int *components, int *answer, int num_edges, int num_vertices){
        int nr = 0, mini, maxi;
        for(int i=0;i<num_edges && nr < num_vertices - 1;++i) {
            printf("Considering ");
            print_edge(edges[i], i);
            putchar('\n');
            if(components[edges[i].first] != components[edges[i].last]){
                printf("Adding ");
                print_edge(edges[i], i);
                putchar('\n');
                answer[nr++] = i;
                if(components[edges[i].first] < components[edges[i].last]){
                    mini = components[edges[i].first];
                    maxi = components[edges[i].last];
                }
                else{
                    maxi = components[edges[i].first];
                    mini = components[edges[i].last];
                }
                for(int j=0;j<num_vertices;++j)
                    if(components[j] == maxi)
                        components[j] = mini;
                print_components(components, num_vertices);
            }
            else {
                printf("Rejecting ");
                print_edge(edges[i], i);
                putchar('\n');
            }
        }
    }
    
    inline int cmp(const void *a, const void *b){
        return (((Edge *)a)->Cost - ((Edge *)b)->Cost);
    }
    
    int answer[grafMAX], components[grafMAX];
    
    int main(){
        Edge *edges;
        int num_edges, num_vertices;
        read_graf(&edges,components,num_edges,num_vertices);
        qsort(edges,num_edges,sizeof(Edge),cmp);
        Kruskal(edges,components,answer,num_edges,num_vertices);
        fprintf(fout,"The cost of the MST is: %d.\n",costMST(edges,answer,num_vertices - 1));
        fclose(fin);
        fclose(fout);
        return 0;
    }