I have to implement a priority queue using binary heap in C for the university assignment. Program should get the n values from input, when value is 0, it should print the ID number(so, if task that was added as 5th element has the highest priority 7, print "5") and remove the highest-priority task from queue, and when value>0 it should add new node. To implement ID's and priority, I used arrays of structs.
The task would be quite simple, if not the fact that it should also print lower ID's if the priority of elements are the same...
I've done my research, but the only advice that I've managed to found is to modify the fragments of typical heap functions (insertkey, heapify) to also look for elements' ID. I've tried to do this, but I have no idea what went wrong - elements are still not sorted in the way I want them to be. I would be grateful for any piece of advice and tips!
Code:
#include <stdio.h>
#define SIZE 99999
int heapsize = 0;
int count = 0;
struct pqueue
{
int priority;
int id;
};
struct pqueue A[SIZE];
void swap(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = temp;
}
void initializearray()
{
for(int i=0; i<SIZE; i++)
{
A[i].priority = 0;
A[i].id = 0;
}
}
void printheap(); //prototype of debugging function
int left(int i)
{
return (i * 2) + 1;
}
int right(int i)
{
return (i * 2) + 2;
}
int parent(int i)
{
return ((i - 1) / 2);
}
void insertkey(int z)
{
heapsize++;
int i = heapsize - 1;
A[i].priority = z;
count++;
A[i].id = count;
while (i != 0 && A[parent(i)].priority < A[i].priority)
{
swap(&A[i].priority, &A[parent(i)].priority);
swap(&A[i].id, &A[parent(i)].id);
i = parent(i);
}
i = heapsize-1;
while(i != 0 && A[parent(i)].priority == A[i].priority && A[parent(i)].id > A[i].id )
{
swap(&A[i].priority, &A[parent(i)].priority);
swap(&A[i].id, &A[parent(i)].id);
i = parent(i);
}
// printheap();
}
void maxheapify(int i)
{
int l = left(i);
int r = right(i);
int largest;
if (l <= heapsize && A[l].priority >= A[i].priority)
{
largest = l;
if(A[l].priority == A[i].priority)
{
if(A[l].id < A[i].id)
{
largest = l;
}
else
{
largest = i;
}
}
}
else
{
largest = i;
}
if (r <= heapsize && A[r].priority >= A[largest].priority)
{
largest = r;
if(A[r].priority == A[largest].priority)
{
if(A[r].id < A[largest].id)
{
largest = r;
}
}
}
if (largest != i)
{
swap(&A[i].priority, &A[largest].priority);
swap(&A[i].id, &A[largest].id);
maxheapify(largest);
}
}
int extractmax()
{
int max = A[0].id;
A[0].priority = A[heapsize-1].priority;
A[0].id = A[heapsize-1].id;
heapsize--;
//printheap();
maxheapify(0);
return max;
}
void printheap() // debug function
{
for(int i = 0; i < heapsize; i++)
{
printf("prio %d id %d \n", A[i].priority, A[i].id);
}
}
int main()
{
int n;
int z;
initializearray();
scanf("%d", &n);
for(int i=0; i<n; i++)
{
scanf("%d", &z);
if(z != 0)
{
insertkey(z);
}
else
{
int local = extractmax();
if(local != 0 && heapsize+1 != 0)
{
printf("%d\n", local);
// printheap();
}
}
}
return 0;
}
Example input:
7
3 0 0 2 8 8 0
Output:
1
3
Example input (here comes the problem:)
10
1 1 1 1 2 0 0 0 0 0
Output:
5
3
2
4
1
Expected output:
5
1
2
3
4
Thank you for your time!
Instead of incorporating the logic directly into the heap implementation, write a comparison function that considers the id if the priorities are the same:
int pqless(const struct pqueue *a, const struct pqueue *b)
{
if (a->priority < b->priority) return 1;
if (a->priority > b->priority) return 0;
return (a->id > b->id);
}
This function returns true if a's priority is less than b's. If both priorities are equal, it returns true if a's id is smaller than b's.
Now update your heap code. Wherever you compare the priorities in the original code, now just call the function:
void insertkey(int z)
{
int i = heapsize++;
A[i].priority = z;
A[i].id = ++count;
while (i != 0 && pqless(&A[parent(i)], &A[i])) {
swap(&A[i].priority, &A[parent(i)].priority);
swap(&A[i].id, &A[parent(i)].id);
i = parent(i);
}
}
void maxheapify(int i)
{
int l = left(i);
int r = right(i);
int largest = i;
if (l <= heapsize && !pqless(&A[l], &A[i])) largest = l;
if (r <= heapsize && !pqless(&A[r], &A[largest]))largest = r;
if (largest != i) {
swap(&A[i].priority, &A[largest].priority);
swap(&A[i].id, &A[largest].id);
maxheapify(largest);
}
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
//#include<igraph.h>
#define NUM_VERTICES1 15000// No. of data for Newman Watts to be used 15000:
//#define strings 10 // No. of base strings to be used 160:
//Function for generating infection rate randomly:
void unifRand(double *x, double *x1, double *x2)
{
int i;
const int n = 200; // 20
srand(unsigned(time(NULL)));
for(i = 0; i < n - 1; i++)
{
//x2[i] = rand()/double(RAND_MAX); //generate random number for choosing the infected neighbors(m):
x[i] = (0.2)+(0.4-0.2)*rand()/double(RAND_MAX);
x2[i] = 0.02; // fix the neighbor m and check:
x1[i] = log(1-x[i]);// Infection rate lambda:
printf("%lf\t%lf\t%lf\t%d\t%d\t\n", x[i], x1[i],x2[i],rand(), RAND_MAX);
}
}
// Function 2:
struct Edge {
int vertex;
struct Edge * next;
};
// Inserts Node to the Linked List by Head Insertion - O(1)
// Returns address of head which is the newly created node.
struct Edge * addEdge(struct Edge * currentHead, int newVertex)
{
struct Edge * newHead
= (struct Edge *) malloc(sizeof(struct Edge));
newHead->vertex = newVertex;
newHead->next = currentHead;
return newHead;
}
int main()
{
FILE *wg = NULL;
FILE *ob = NULL;
wg = fopen("ncwang1.txt","w");
ob = fopen("obs.txt","w");
if(wg == NULL)
{
printf("Error in opening file wg!\n");
}
if(ob == NULL)
{
printf("Error in opening file ob!\n");
}
int vertices = 200, edges = 400, i; // 20,50:(100,50)
int strings = 160;
int nobs = 10;
int v1, v2;
double j;
int k;
double t=0.0;
double dt=0.1;
double b;
double x[vertices], x1[vertices];
double x2[vertices];
unifRand(x,x1,x2);
// printf("Enter the Number of Vertices -\n");
// scanf("%d", &vertices);
//printf("\nEnter the Number of Edges -\n");
// scanf("%d", &edges);
struct Edge * adjacencyList[vertices + 1];
// Size is made (vertices + 1) to use the
// array as 1-indexed, for simplicity
// initialize array:
for (i = 0; i <= vertices; ++i) {
adjacencyList[i] = NULL;
}
for (i = 0; i <= edges; ++i) {
//scanf(%d%d", &v1, &v2);
v1 = rand()%200;
v2 = rand()%200;
// Adding edge v1 --> v2
// Add edge from v1 --> v2
if(v1 != v2)
adjacencyList[v1] = addEdge(adjacencyList[v1], v2);
// Adding edge v2 --> v1
// Remove this if you want a Directed Graph
adjacencyList[v2] = addEdge(adjacencyList[v2], v1);
}
// Printing Adjacency List
printf("\nAdjacency List -\n\n");
for(j = 0; j < strings; j++){
for (i = 0; i <= vertices; ++i) {
printf("adjacencyList[%d] -> ", i);
struct Edge * traverse = adjacencyList[i];
while (traverse != NULL)
{
b = (double)j/vertices;
fprintf(wg,"%d \t%d \t\t%0.6lf\t\t%0.1lf\t\t%0.8lf\t\n", i, traverse->vertex,-(x1[i]*(traverse->vertex))/100,b,
x[i]);
//fprintf(ob,"%d\t%0.2lf\t%0.1lf\n",k,(-log(1-x[i])*(traverse->vertex)),b);
printf("%d -> ", traverse->vertex);
traverse = traverse->next;
}
printf("NULL\n");
}
}
return 0;
fclose(wg);
fclose(ob);
wg = NULL;
ob = NULL;
}
I have written the above code for a network reconstruction performance from a reseach paper. I have to plot 'b' versus (-log(1-x[i])*(traverse->vertex)) from the output. The authors of the paper have mentioned that "the results are obtained by ensemble averaging over 10 independent realizations. How I can implement this in my code. As I am new to statistical physics, I do not know how to implement. Any suggestions will be helpful. The current output gives only a single line at b = 0.1, 0.2..1.0 which is not the expected output.c
i am trying to implement a linked-list in C with the aim to do a BFS on it.
The input for the list should look like this:
a-bc
b-a
c-a
which represents a list looking like this:
a
/ \
b c
now, my problem is that I cannot read the variable name defined in my Vertex struct. My program segfaults with Access Reading Violation. While printf("%s", s) takes a char *, casting the name to a char* doesn't help. The error takes place before the char is even accessed?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Vertex Vertex;
typedef struct Vertex
{
char name;
int visited;
int distance;
Vertex* next;
} Vertex;
struct Vertex* AddVertex(Vertex* head, char newVertexName)
{
Vertex* newHead = malloc(sizeof(Vertex));
newHead->name = newVertexName;
printf("added vertex named: %s", newHead->name); // causing the error
newHead->next = head;
newHead->visited = 0;
newHead->distance = 0;
return newHead;
}
int main()
{
// BFS
char s[100];
int l = 0;
const int nNrOfVerts = 27;
Vertex* adjList[28];
// initialise array of pointers
for(int i = 0; i <= nNrOfVerts; ++i)
{
adjList[i] = NULL;
}
// fill vertices with user data
for(int i = 1; i <= nNrOfVerts; ++i)
{
printf("enter %d vert: ", i);
if(scanf("%s", &s) != 1)
{
break;
}
l = strlen(s);
if(l > 2)
{
for(int k = 0; k < l; ++k)
{
// increment to accustom for the - seperator
if(1 == k)
{
k = 2;
}
adjList[i] = AddVertex(adjList[i], s[k]);
}
}
for(int k = 0; k < 100; ++k)
{
s[k] = NULL;
}
}
bfs(adjList);
// printing the list
for(int i = 1; i <= l; ++i)
{
for(int j = 0; j <= nNrOfVerts; ++j)
{
if(adjList[j]->distance == i)
{
printf("Level: %d is: %s", i, adjList[j]->name);
}
printf("No node for dist: %d", i);
}
}
return 0;
}
How can I access the value of newHead->name or adjList[i]->name for that matter? The interesting thing is, if I try to access adjList[i]->distance the correct integer is returned...
You declared name as a char but then you try to print it as a character :
printf("added vertex named: %s", newHead->name);
Change the %s to %c :
printf("added vertex named: %c", newHead->name);
or change your name to a char *.
Hi Guys i have edited the questions.Here is my entire code.I have given basic amount of readability to my program.I hope u guys can understand the program.
#include<stdio.h>
#include<stdlib.h>
int Max_Min(int,int,int,int *, int *);
int *Max,Number;
int main()
{
int n1, n2,Maximum_Element=0,*Max;
int i = 0, j = 0;
scanf("%d",&Number);
Max =(int *) malloc(sizeof(int)*Number);//Array Max is created
for (int k = 0;k <(Number/2);k++)
{
scanf("%d", &n1);
scanf("%d", &n2);
Max[k] = Max_Min(0,1,0,&n1,&n2);//Passing integer elements n1,n2 with flag 0
}
Maximum_Element=Max_Min(1,1,((sizeof(Max)*Number)/8),Max,Min);//Passing array elements Max,Min with flag 1 to function Max_Min
printf("Maximum_Element=%d", Maximum_Element);
return 0;
}
int Max_Min(int flag,int Max_Min_flag,int length,int *n1,int *n2)//n1 and n2 should be able to handle array and integers
{
int i=0,j = 0,k1,k2,Min1 = 0, Min2 = 0,count=0, Not_Zero = 0,x=0,y=0, *New_Max = 0,*New_Min;
/*Recursive Loop for splitting the array elements and calling the array */
if (flag == 1)
{
New_Max = (int *)(malloc(sizeof(int)*length));
for (;i <= ((length) / 2);i = i + 2)//
{
k1 = n1[i];
j = i + 1;
if (j <= ((length + 1) / 2))
{
k2 = n1[j];
New_Max[count] = Max_Min(0, 1, 0, &k1, &k2);//It is passing integer elements with flag 0 to function Max_Min
count++;
}
}
New_Max[count] = n1[j + 1];
for (int i = 0;i < count + 1;i++)
{
**/* Problem is assigning Max[i]=New_Max[i] is not getting assigned*/**
Max[i] = New_Max[i];//Copying from New_Max to Max because New_Max will be overwritten,so possible chaunce of dataloss
Not_Zero++;
}
while ((sizeof(Max) / 4 - (Not_Zero))>0)
{
Max[Not_Zero] = 0;
Not_Zero++;
}
/*Logic for calling recursive functions based on the count*/
if (count > 1)
{
count--;
Max_Min(1, 1, count, Max, Min);//Calling Recursive function by Passing Entire Arrays with flag 1.
}
else if (count == 1 && Max[1] == 0)
{
*n1 = Max[0];
*n2 = Min[0];
}
else if (count == 1 && Max[2] == 0)
{
Max_Min(1, 1, count + 1, Max, Min);
count--;
}
}
/*Logic for Finding Maximum & Minimum element is present down*/
if (flag == 0)
{
printf("flag");
if (Max_Min_flag == 1)
{
if (*n1 > *n2)
{
}
else if ((*n1 < *n2) && Max_Min_flag == 1)
{
int temp = 0;
temp = *n1;//5
*n1 = *n2;//7
*n2 = temp;//5
}
}
else if (Max_Min_flag == 2)
{
if (*n1 > *n2)//7>2
{
int temp = 0;
temp = *n1;//2
*n1 = *n2;//2
*n2 = temp;//2,7
}
else if (*n1 < *n2)
{
}
}
}
return *n1;//7
}
Problem is assigning Max[i]=New_Max[i] in function Max_Min().It shows Run time error as "Access violation writing location 0x00000000."
First you need to #include <stdlib.h> to use malloc
You must declare your function before using it.
func must return int*.
Also in func "n", first "Max", and second "Max" needs to be the same variable. Rename "n" to "Max"
This is the code corrected with an extra printf;
#include <stdio.h>
#include <stdlib.h>
int *Max,Number=5;
int* func(int *Max)
{
for(int j=0;j<5;j++)
Max[j]=j;//Its not working in this line
return Max;
}
int main()
{
Max=(int *) malloc(sizeof(int)*Number);
for(int i=0;i<5;i++)
Max[i]=i;
int* x = func(Max);
for(int i=0;i<5;i++)
printf("%d", x[i]);
}
The following contains only minor adaptations of your code and it runs fine:
int *func(int *n);
int *Max,Number=5;
int main()
{
int *x,i;
Max=(int *) malloc(sizeof(int)*Number);
for(i=0;i<Number;i++)
Max[i]=i;
x=func(Max);
free(Max);
return(0);
}
int *func(int *n)
{
int j;
for (j=0;j<Number;j++)
n[j]=Number-j; // reverse the number, just to check
return Max;
}
I have this question for my programming class which I have been struggling to complete for the past day ... and I have no real idea what to do.
I understand the basic concept of Prim's algorithm:
1. Start at an arbitrary node (the first node will do) and
add all of its links onto a list.
2. Add the smallest link (which doesn't duplicate an existing path)
in the MST, to the Minimum Spanning Tree.
Remove this link from the list.
3. Add all of the links from the newly linked node onto the list
4. repeat steps 2 & 3 until MST is achieved
(there are no nodes left unconnected).
I have been given this implementation of a Graph (using an Adjacency List) to implement Prim's algorithm on. The problem is I don't really understand the implementation. My understanding of the implementation so far is as follows:
Being an adjacency list, we have all the nodes in array form: Linked to this is a list of links, containing details of the weight, the destination, and a pointer to the rest of the links of the specific node:
Something that looks a bit like this:
[0] -> [weight = 1][Destination = 3] -> [weight = 6][Destination = 4][NULL]
[1] -> [weight = 4][Destination = 3][NULL]
and so on...
We also have an "Edge" struct, which I think is supposed to make things simpler for the implementation, but I'm not really seeing it.
Here is the code given:
GRAPH.h interface:
typedef struct {
int v;
int w;
int weight;
} Edge;
Edge EDGE (int, int, int);
typedef struct graph *Graph;
Graph GRAPHinit (int);
void GRAPHinsertE (Graph, Edge);
void GRAPHremoveE (Graph, Edge);
int GRAPHedges (Edge [], Graph g);
Graph GRAPHcopy (Graph);
void GRAPHdestroy (Graph);
int GRAPHedgeScan (Edge *);
void GRAPHEdgePrint (Edge);
int GRAPHsearch (Graph, int[]);
Graph GRAPHmst (Graph);
Graph GRAPHmstPrim (Graph);
#define maxV 8
GRAPH.c implementation:
#include <stdlib.h>
#include <stdio.h>
#include "GRAPH.h"
#define exch(A, B) { Edge t = A; A = B; B = t; }
#define max(A,B)(A>B?A:B)
#define min(A,B)(A<B?A:B)
typedef struct node *link;
struct node {
int v;
int weight;
link next;
};
struct graph {
int V;
int E;
link *adj;
};
static void sortEdges (Edge *edges, int noOfEdges);
static void updateConnectedComponent (Graph g, int from, int to, int newVal, int *connectedComponent);
Edge EDGE (int v, int w, int weight) {
Edge e = {v, w, weight};
return e;
}
link NEW (int v, int weight, link next) {
link x = malloc (sizeof *x);
x->v = v;
x->next = next;
x->weight = weight;
return x;
}
Graph GRAPHinit (int V) {
int v;
Graph G = malloc (sizeof *G);
// Set the size of the graph, = number of verticies
G->V = V;
G->E = 0;
G->adj = malloc (V * sizeof(link));
for (v = 0; v < V; v++){
G->adj[v] = NULL;
}
return G;
}
void GRAPHdestroy (Graph g) {
// not implemented yet
}
void GRAPHinsertE(Graph G, Edge e){
int v = e.v;
int w = e.w;
int weight = e.weight;
G->adj[v] = NEW (w, weight, G->adj[v]);
G->adj[w] = NEW (v, weight, G->adj[w]);
G->E++;
}
void GRAPHremoveE(Graph G, Edge e){
int v = e.v;
int w = e.w;
link *curr;
curr = &G->adj[w];
while (*curr != NULL){
if ((*curr)->v == v) {
(*curr) = (*curr)->next;
G->E--;
break;
}
curr= &((*curr)->next);
}
curr = &G->adj[v];
while (*curr != NULL){
if ((*curr)->v == w) {
(*curr) = (*curr)->next;
break;
}
curr= &((*curr)->next);
}
}
int GRAPHedges (Edge edges[], Graph g) {
int v, E = 0;
link t;
for (v = 0; v < g->V; v++) {
for (t = g->adj[v]; t != NULL; t = t->next) {
if (v < t->v) {
edges[E++] = EDGE(v, t->v, t->weight);
}
}
}
return E;
}
void GRAPHEdgePrint (Edge edge) {
printf ("%d -- (%d) -- %d", edge.v, edge.weight, edge.w);
}
int GRAPHedgeScan (Edge *edge) {
if (edge == NULL) {
printf ("GRAPHedgeScan: called with NULL \n");
abort();
}
if ((scanf ("%d", &(edge->v)) == 1) &&
(scanf ("%d", &(edge->w)) == 1) &&
(scanf ("%d", &(edge->weight)) == 1)) {
return 1;
} else {
return 0;
}
}
// Update the CC label for all the nodes in the MST reachable through the edge from-to
// Assumes graph is a tree, will not terminate otherwise.
void updateConnectedComponent (Graph g, int from, int to, int newVal, int *connectedComponent) {
link currLink = g->adj[to];
connectedComponent[to] = newVal;
while (currLink != NULL) {
if (currLink->v != from) {
updateConnectedComponent (g, to, currLink->v, newVal, connectedComponent);
}
currLink = currLink->next;
}
}
// insertion sort, replace with O(n * lon n) alg to get
// optimal work complexity for Kruskal
void sortEdges (Edge *edges, int noOfEdges) {
int i;
int l = 0;
int r = noOfEdges-1;
for (i = r-1; i >= l; i--) {
int j = i;
while ((j < r) && (edges[j].weight > edges[j+1].weight)) {
exch (edges[j], edges[j+1]);
j++;
}
}
}
Graph GRAPHmst (Graph g) {
Edge *edgesSorted;
int i;
int *connectedComponent = malloc (sizeof (int) * g->V);
int *sizeOfCC = malloc (sizeof (int) * g->V);
Graph mst = GRAPHinit (g->V);
edgesSorted = malloc (sizeof (*edgesSorted) * g->E);
GRAPHedges (edgesSorted, g);
sortEdges (edgesSorted, g->E);
// keep track of the connected component each vertex belongs to
// in the current MST. Initially, MST is empty, so no vertex is
// in an MST CC, therefore all are set to -1.
// We also keep track of the size of each CC, so that we're able
// to identify the CC with fewer vertices when merging two CCs
for (i = 0; i < g->V; i++) {
connectedComponent[i] = -1;
sizeOfCC[i] = 0;
}
int currentEdge = 0; // the shortest edge not yet in the mst
int mstCnt = 0; // no of edges currently in the mst
int v, w;
// The MST can have at most min (g->E, g->V-1) edges
while ((currentEdge < g->E) && (mstCnt < g->V)) {
v = edgesSorted[currentEdge].v;
w = edgesSorted[currentEdge].w;
printf ("Looking at Edge ");
GRAPHEdgePrint (edgesSorted[currentEdge]);
if ((connectedComponent[v] == -1) ||
(connectedComponent[w] == -1)) {
GRAPHinsertE (mst, edgesSorted[currentEdge]);
mstCnt++;
if (connectedComponent[v] == connectedComponent[w]) {
connectedComponent[v] = mstCnt;
connectedComponent[w] = mstCnt;
sizeOfCC[mstCnt] = 2; // initialise a new CC
} else {
connectedComponent[v] = max (connectedComponent[w], connectedComponent[v]);
connectedComponent[w] = max (connectedComponent[w], connectedComponent[v]);
sizeOfCC[connectedComponent[w]]++;
}
printf (" is in MST\n");
} else if (connectedComponent[v] == connectedComponent[w]) {
printf (" is not in MST\n");
} else {
printf (" is in MST, connecting two msts\n");
GRAPHinsertE (mst, edgesSorted[currentEdge]);
mstCnt++;
// update the CC label of all the vertices in the smaller CC
// (size is only important for performance, not correctness)
if (sizeOfCC[connectedComponent[w]] > sizeOfCC[connectedComponent[v]]) {
updateConnectedComponent (mst, v, v, connectedComponent[w], connectedComponent);
sizeOfCC[connectedComponent[w]] += sizeOfCC[connectedComponent[v]];
} else {
updateConnectedComponent (mst, w, w, connectedComponent[v], connectedComponent);
sizeOfCC[connectedComponent[v]] += sizeOfCC[connectedComponent[w]];
}
}
currentEdge++;
}
free (edgesSorted);
free (connectedComponent);
free (sizeOfCC);
return mst;
}
// my code so far
Graph GRAPHmstPrim (Graph g) {
// Initializations
Graph mst = GRAPHinit (g->V); // graph to hold the MST
int i = 0;
int nodeIsConnected[g->V];
// initially all nodes are not connected, initialize as 0;
for(i = 0; i < g->V; i++) {
nodeIsConnected[i] = 0;
}
// extract the first vertex from the graph
nodeIsConnected[0] = 1;
// push all of the links from the first node onto a temporary list
link tempList = newList();
link vertex = g->adj[0];
while(vertex != NULL) {
tempList = prepend(tempList, vertex);
vertex = vertex->next;
}
// find the smallest link from the node;
mst->adj[0] =
}
// some helper functions I've been writing
static link newList(void) {
return NULL;
}
static link prepend(link list, link node) {
link temp = list;
list = malloc(sizeof(list));
list->v = node->v;
list->weigth = node->weight;
list->next = temp;
return list;
}
static link getSmallest(link list, int nodeIsConnected[]) {
link smallest = list;
while(list != NULL){
if((list->weight < smallest->weight)&&(nodeIsConnected[list->v] == 0)) {
smallest = list;
}
list = list->next;
}
if(nodeIsConnected[smallest->v] != 0) {
return NULL;
} else {
return smallest;
}
}
For clarity, file to obtain test data from file:
#include <stdlib.h>
#include <stdio.h>
#include "GRAPH.h"
// call with graph_e1.txt as input, for example.
//
int main (int argc, char *argv[]) {
Edge e, *edges;
Graph g, mst;
int graphSize, i, noOfEdges;
if (argc < 2) {
printf ("No size provided - setting max. no of vertices to %d\n", maxV);
graphSize = maxV;
} else {
graphSize = atoi (argv[1]);
}
g = GRAPHinit (graphSize);
printf ("Reading graph edges (format: v w weight) from stdin\n");
while (GRAPHedgeScan (&e)) {
GRAPHinsertE (g, e);
}
edges = malloc (sizeof (*edges) * graphSize * graphSize);
noOfEdges = GRAPHedges (edges, g);
printf ("Edges of the graph:\n");
for (i = 0; i < noOfEdges; i++) {
GRAPHEdgePrint (edges[i]);
printf ("\n");
}
mst = GRAPHmstPrim (g);
noOfEdges = GRAPHedges (edges, mst);
printf ("\n MST \n");
for (i = 0; i < noOfEdges; i++) {
GRAPHEdgePrint (edges[i]);
printf ("\n");
}
GRAPHdestroy (g);
GRAPHdestroy (mst);
free (edges);
return EXIT_SUCCESS;
}
Thanks in advance.
Luke
files in full: http://www.cse.unsw.edu.au/~cs1927/12s2/labs/13/MST.html
UPDATE: I have had another attempt at this question. Here is the updated code (One edit above to change the graph_client.c to use "GRAPHmstPrim" function that I have written.
GRAPH_adjlist.c::
#include <stdlib.h>
#include <stdio.h>
#include "GRAPH.h"
#define exch(A, B) { Edge t = A; A = B; B = t; }
#define max(A,B)(A>B?A:B)
#define min(A,B)(A<B?A:B)
typedef struct _node *link;
struct _node {
int v;
int weight;
link next;
}node;
struct graph {
int V;
int E;
link *adj;
};
typedef struct _edgeNode *edgeLink;
struct _edgeNode {
int v;
int w;
int weight;
edgeLink next;
}edgeNode;
static void sortEdges (Edge *edges, int noOfEdges);
static void updateConnectedComponent (Graph g, int from, int to, int newVal, int *connectedComponent);
Edge EDGE (int v, int w, int weight) {
Edge e = {v, w, weight};
return e;
}
link NEW (int v, int weight, link next) {
link x = malloc (sizeof *x);
x->v = v;
x->next = next;
x->weight = weight;
return x;
}
Graph GRAPHinit (int V) {
int v;
Graph G = malloc (sizeof *G);
G->V = V;
G->E = 0;
G->adj = malloc (V * sizeof(link));
for (v = 0; v < V; v++){
G->adj[v] = NULL;
}
return G;
}
void GRAPHdestroy (Graph g) {
// not implemented yet
}
void GRAPHinsertE(Graph G, Edge e){
int v = e.v;
int w = e.w;
int weight = e.weight;
G->adj[v] = NEW (w, weight, G->adj[v]);
G->adj[w] = NEW (v, weight, G->adj[w]);
G->E++;
}
void GRAPHremoveE(Graph G, Edge e){
int v = e.v;
int w = e.w;
link *curr;
curr = &G->adj[w];
while (*curr != NULL){
if ((*curr)->v == v) {
(*curr) = (*curr)->next;
G->E--;
break;
}
curr= &((*curr)->next);
}
curr = &G->adj[v];
while (*curr != NULL){
if ((*curr)->v == w) {
(*curr) = (*curr)->next;
break;
}
curr= &((*curr)->next);
}
}
int GRAPHedges (Edge edges[], Graph g) {
int v, E = 0;
link t;
for (v = 0; v < g->V; v++) {
for (t = g->adj[v]; t != NULL; t = t->next) {
if (v < t->v) {
edges[E++] = EDGE(v, t->v, t->weight);
}
}
}
return E;
}
void GRAPHEdgePrint (Edge edge) {
printf ("%d -- (%d) -- %d", edge.v, edge.weight, edge.w);
}
int GRAPHedgeScan (Edge *edge) {
if (edge == NULL) {
printf ("GRAPHedgeScan: called with NULL \n");
abort();
}
if ((scanf ("%d", &(edge->v)) == 1) &&
(scanf ("%d", &(edge->w)) == 1) &&
(scanf ("%d", &(edge->weight)) == 1)) {
return 1;
} else {
return 0;
}
}
// Update the CC label for all the nodes in the MST reachable through the edge from-to
// Assumes graph is a tree, will not terminate otherwise.
void updateConnectedComponent (Graph g, int from, int to, int newVal, int *connectedComponent) {
link currLink = g->adj[to];
connectedComponent[to] = newVal;
while (currLink != NULL) {
if (currLink->v != from) {
updateConnectedComponent (g, to, currLink->v, newVal, connectedComponent);
}
currLink = currLink->next;
}
}
// insertion sort, replace with O(n * lon n) alg to get
// optimal work complexity for Kruskal
void sortEdges (Edge *edges, int noOfEdges) {
int i;
int l = 0;
int r = noOfEdges-1;
for (i = r-1; i >= l; i--) {
int j = i;
while ((j < r) && (edges[j].weight > edges[j+1].weight)) {
exch (edges[j], edges[j+1]);
j++;
}
}
}
Graph GRAPHmst (Graph g) {
Edge *edgesSorted;
int i;
int *connectedComponent = malloc (sizeof (int) * g->V);
int *sizeOfCC = malloc (sizeof (int) * g->V);
Graph mst = GRAPHinit (g->V);
edgesSorted = malloc (sizeof (*edgesSorted) * g->E);
GRAPHedges (edgesSorted, g);
sortEdges (edgesSorted, g->E);
// keep track of the connected component each vertex belongs to
// in the current MST. Initially, MST is empty, so no vertex is
// in an MST CC, therefore all are set to -1.
// We also keep track of the size of each CC, so that we're able
// to identify the CC with fewer vertices when merging two CCs
for (i = 0; i < g->V; i++) {
connectedComponent[i] = -1;
sizeOfCC[i] = 0;
}
int currentEdge = 0; // the shortest edge not yet in the mst
int mstCnt = 0; // no of edges currently in the mst
int v, w;
// The MST can have at most min (g->E, g->V-1) edges
while ((currentEdge < g->E) && (mstCnt < g->V)) {
v = edgesSorted[currentEdge].v;
w = edgesSorted[currentEdge].w;
printf ("Looking at Edge ");
GRAPHEdgePrint (edgesSorted[currentEdge]);
if ((connectedComponent[v] == -1) ||
(connectedComponent[w] == -1)) {
GRAPHinsertE (mst, edgesSorted[currentEdge]);
mstCnt++;
if (connectedComponent[v] == connectedComponent[w]) {
connectedComponent[v] = mstCnt;
connectedComponent[w] = mstCnt;
sizeOfCC[mstCnt] = 2; // initialise a new CC
} else {
connectedComponent[v] = max (connectedComponent[w], connectedComponent[v]);
connectedComponent[w] = max (connectedComponent[w], connectedComponent[v]);
sizeOfCC[connectedComponent[w]]++;
}
printf (" is in MST\n");
} else if (connectedComponent[v] == connectedComponent[w]) {
printf (" is not in MST\n");
} else {
printf (" is in MST, connecting two msts\n");
GRAPHinsertE (mst, edgesSorted[currentEdge]);
mstCnt++;
// update the CC label of all the vertices in the smaller CC
// (size is only important for performance, not correctness)
if (sizeOfCC[connectedComponent[w]] > sizeOfCC[connectedComponent[v]]) {
updateConnectedComponent (mst, v, v, connectedComponent[w], connectedComponent);
sizeOfCC[connectedComponent[w]] += sizeOfCC[connectedComponent[v]];
} else {
updateConnectedComponent (mst, w, w, connectedComponent[v], connectedComponent);
sizeOfCC[connectedComponent[v]] += sizeOfCC[connectedComponent[w]];
}
}
currentEdge++;
}
free (edgesSorted);
free (connectedComponent);
free (sizeOfCC);
return mst;
}
edgeLink newEdgeList(void) {
return NULL;
}
edgeLink addEdgeList(edgeLink list, int node, link edge) {
printf("EdgeListStart");
edgeLink temp = list;
list = malloc(sizeof(edgeNode));
list->w = node;
list->v = edge->v;
list->weight = edge->weight;
list->next = temp;
printf("EdgeListEnd");
return list;
}
edgeLink findSmallest(edgeLink waitList, int nodeIsConnected[]) {
printf("SmallestSTart");
edgeLink smallest = waitList;
int small = 99999;
while(waitList != NULL) {
if((waitList->weight < small)&&(nodeIsConnected[waitList->v] == 0)) {
smallest = waitList;
small = smallest->weight;
} else {
printf("\n\n smallest already used %d", waitList->v);
}
waitList = waitList->next;
}
printf("SmallestEnd");
if(nodeIsConnected[smallest->v] == 0){
return smallest;
} else {
printf("Returning NULL");
return NULL;
}
}
link addList(edgeLink smallest, link list, int v) {
printf(":istsatt");
link temp = list;
list = malloc(sizeof(node));
list->v = v;
list->weight = smallest->weight;
list->next = temp;
printf("Listend");
return list;
}
Graph GRAPHmstPrim (Graph g) {
Graph mst = GRAPHinit (g->V); // graph to hold the MST
int i = 0;
int v = 0;
int w = 0;
int nodeIsConnected[g->V]; // array to hold whether a vertex has been added to MST
int loopStarted = 0;
edgeLink smallest = NULL;
// initially all nodes are not in the MST
for(i = 0; i < g->V; i++) {
nodeIsConnected[i] = 0;
}
while((smallest != NULL)||(loopStarted == 0)) {
printf("v is : %d", v);
// add the very first node to the MST
nodeIsConnected[v] = 1;
loopStarted = 1;
// push all of its links onto the list
link vertex = g->adj[v];
edgeLink waitList = newEdgeList();
while(vertex != NULL) {
waitList = addEdgeList(waitList, v, vertex);
vertex = vertex->next;
}
// find the smallest edge from the list
// which doesn't duplicate a connection
smallest = findSmallest(waitList, nodeIsConnected);
// no nodes don't duplicate a connection
// return the current MST
if(smallest == NULL){
return mst;
}
// otherwise add the attributes to the MST graph
w = smallest->w;
v = smallest->v;
mst->adj[v] = addList(smallest, mst->adj[v], w);
mst->adj[w] = addList(smallest, mst->adj[w], v);
}
return mst;
}
Summary of changes:
- Added edgeList to hold the edges that may be entered into the MST
- Array nodeIsConnected[] to track whether a node is in the MST
- Function to select the smallest node. If there is no node which doesn't duplicate a link this returns NULL
Seeing as this seems homework, I'm not going to give the entire answer in code. Your code seems to be on the right track. The next step you need is indeed to add the smallest link from your temporary list to to your mst. By adding the smallest one from your list, you are actually connecting your (partially built) mst to a node that is not yet in your mst. The link with the smallest weight will always be the cheapest way to connect the nodes in your mst to the other nodes.
When you add the smallest link, you are adding a node to the partially built tree and you need to update your temporary list. You need to add all the links of your new node to the list. Once you've done that, your temporary list contains all links of all nodes in your partially built mst. You continue that process of adding nodes until all nodes are in your mst.
When adding the cheapest link, you need to check if you are connecting a new node to your mst. The cheapest link could be connecting 2 nodes that are already in your mst. If so, that link needs to be skipped and you take the next cheapest one. There are actually several ways of handling this. You could maintain a set/vector of nodes that are already in your mst, maintain a vector of booleans to track the status of a node or make sure your temporary list only contains links that connect new nodes (although this is the most intensive approach).