Sunday, July 13, 2014

Minimum Spanning Tree in C

One of my projects in algorithms class was to create a MST in C.  I was given 5 sample inputs with answers, and 5 without answers.  I had to create the MST using two different algorithms: Prim and Kruskal.  The complete folder with the tests and results can be downloaded here.  I completed this project in about 5 days.
 //Author: Kevin Achenbach  
 //Date: 4/20/14  
 //Description: Given coordinates, will find the total distance of a MST  
 //                               using Prim and Kruskals MST   
 #include <stdio.h>  
 #include <math.h>  
 //distance can not be greater than INF  
 #define INF 100000  
 //probably unneccessary, just make array if time  
 struct Vertex {  
      int rep;  
 };  
 void prim(int numinput, double graph[][2]);  
 void kruskal(int numinput, double graph[][2]);  
 void unionVert(struct Vertex[],int len, int rep1, int rep2);   
 /*      Expected input:  
           # of test cases  
           # of coordinates  
           x1coord y2coord  
           etc..  
 */  
 int main() {  
      int testcase, numinput, i, j;  
      scanf("%d", &testcase);  
      for(j=0; j<testcase; j++){  
           scanf("%d", &numinput);  
           double graph[numinput][2];  
           //get input and place in graph array  
           for(i=0;i<numinput; i++) {  
                scanf("%lf", &graph[i][0]);  
                scanf("%lf", &graph[i][1]);  
           }  
           prim(numinput, graph);  
           kruskal(numinput, graph);  
      }  
      return 0;  
 }  
 struct Edge {  
      double weight;  
      int p1, p2;  
 };  
 // Kruskal union, makes 2 trees into 1  
 void unionVert(struct Vertex* vertGraph,int len, int rep1, int rep2) {  
      int i;  
      if(rep1<rep2)  
           for(i=0; i<len; i++) {  
                if(vertGraph[i].rep == rep2)     {  
                     vertGraph[i].rep = rep1;   
                }  
           }  
      else {  
           for(i=0; i<len; i++) {  
                if(vertGraph[i].rep == rep1) {  
                     vertGraph[i].rep = rep2;  
                }  
           }  
      }       
 }  
 void kruskal(int numinput, double graph[][2]) {  
      //pg 631 MST-Kruskal ALG  
      //First checks for <2 inputs  
      if(!numinput) {  
           printf("\nError: Number of inputs must be greater than 0\n");  
           return;  
      }  
      else if(numinput == 1) {  
           printf("\n0.00\n");  
           return;  
      }  
      //total number of unique distances is given by n(n-1)/2  
      int totalNumDist = (numinput*(numinput-1))/2;  
      //contains all edges  
      struct Edge edgeGraph[totalNumDist];  
      int count = 0;  
      int i,j;  
      double first,second,totalDist;  
      //map out the distances  
      //only write distances once as opposed to prim's  
      for(i=0; i<numinput; i++) {  
           for(j=0; j<numinput; j++)     {  
                     if(i<j) {  
                          first = graph[i][0]-graph[j][0];  
                          first = pow(first,2);  
                          second = graph[i][1]-graph[j][1];  
                          second = pow(second,2);  
                          first += second;  
                          edgeGraph[count].weight= sqrt(first);  
                          edgeGraph[count].p1 = i;  
                          edgeGraph[count].p2 = j;  
                          count++;  
                          }  
                }  
      }  
      //insertion sort of the edges  
      double storeWeight;  
      int storeP1, storeP2;  
      //insertion sort to put lowest edge weights at top of the array  
      for(i=1; i<totalNumDist; i++) {  
           j=i;  
           while(j>0 && edgeGraph[j].weight < edgeGraph[j-1].weight) {  
                storeWeight = edgeGraph[j].weight;  
                storeP1 = edgeGraph[j].p1;  
                storeP2 = edgeGraph[j].p2;  
                edgeGraph[j].weight = edgeGraph[j-1].weight;  
                edgeGraph[j].p1 = edgeGraph[j-1].p1;  
                edgeGraph[j].p2 = edgeGraph[j-1].p2;  
                edgeGraph[j-1].weight = storeWeight;  
                edgeGraph[j-1].p1 = storeP1;  
                edgeGraph[j-1].p2 = storeP2;  
                j--;  
           }  
      }  
      struct Vertex vertGraph[numinput];  
      //each vert is a seperate tree  
      for(i=0; i<numinput; i++) {  
           vertGraph[i].rep = i;  
      }  
      //check off the first edge  
      totalDist = edgeGraph[0].weight;  
      //intial smallest edge is used to connect the seperate trees  
      unionVert(vertGraph, numinput, edgeGraph[0].p1, edgeGraph[0].p2);  
      //go through edges, smallest to largest, if they are unique trees  
      //union them into the same tree  
      for(i=1; i<totalNumDist;i++) {  
           if(vertGraph[edgeGraph[i].p1].rep != vertGraph[edgeGraph[i].p2].rep) {  
                totalDist += edgeGraph[i].weight;  
                unionVert(vertGraph, numinput, vertGraph[edgeGraph[i].p1].rep, vertGraph[edgeGraph[i].p2].rep);  
           }  
      }            
           printf("\n%.2lf\n", totalDist);  
 }  
 void prim(int numinput, double graph[][2]) {  
      //initial check for <2 input       
      if(!numinput) {  
           printf("\nError: Number of inputs must be greater than 0");  
           return;  
      }  
      else if(numinput == 1) {  
           printf("\n0.00\n");  
           return;  
      }  
      //keeps track of inputs already used  
      int inMST[numinput];       
      double distances[numinput][numinput];  
      int i,j,key;  
      double first, second;  
      double total = 0;  
      int done = 0;  
      //first find distance between all points  
      //This is a slower version than kruskal's  
      //it repeats distances  
      for(i=0; i<numinput; i++)     {  
           //set all inMST to 0            
           inMST[i] = 0;  
           for(j=0; j<numinput; j++)     {  
                if(i==j)  
                     distances[i][i] == INF;  
                else {  
                     first = graph[i][0]-graph[j][0];  
                     first = pow(first,2);  
                     second = graph[i][1]-graph[j][1];  
                     second = pow(second,2);  
                     first += second;  
                     distances[i][j]= sqrt(first);  
                     }  
           }  
      }  
      //Assume that vertex 0 is the starting point  
      inMST[0] = 1;  
      int count = 1;  
      //waits until every dist has been checked  
      while(!done) {  
           //Num of vertices in MST  
           double minDist = INF;  
           int startVert = 0;  
           int endVert = 0;  
           //find the closest vertex not yet in MST  
           for(i=0; i < numinput; i++) {  
                if(inMST[i]) {  
                     for(j=0; j < numinput; j++) {  
                          if(i!=j && distances[i][j] < minDist && inMST[j] == 0) {  
                               startVert = i;  
                               endVert = j;  
                               minDist = distances[i][j];  
                          }  
                     }  
                }       
           }  
           //found next vertex mark it off and add edge to total  
           inMST[endVert] = 1;  
           total += minDist;  
           distances[startVert][endVert] = INF;  
           distances[endVert][startVert] = INF;  
           count++;  
           if(count >= numinput)  
                done++;  
      }  
      printf("\n%.2lf\n", total);  
 }  

No comments:

Post a Comment