so i've been working on a small function(part of a bigger program) that basically does the following:
define a list and the number of elements N, then input N elements. after this, input a value X;
I have to 'split' / re-order the list in a way so that its elements with value < X are in the beginning, in their relative order and the ones with higher value than X come after; eg.:
Input:
list 6
2 5 6 4 3 1
X 3
Output:
2 3 1 5 6 4
my code and list structure are down below:
(the partition function is at the bottom, just above the main function)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_STRING_SIZE 64
typedef struct ll_node_t
{
void* data;
struct ll_node_t* next;
} ll_node_t;
typedef struct linked_list_t
{
ll_node_t* head;
unsigned int data_size;
unsigned int size;
} linked_list_t;
linked_list_t*
ll_create(unsigned int data_size)
{
linked_list_t* list = malloc(sizeof(list));
// err handle
list->head = NULL;
list->data_size = data_size;
list->size = 0;
return list;
}
void
ll_add_nth_node(linked_list_t* list, unsigned int n, const void* new_data)
{
if(n < 0) exit(0);
ll_node_t* new_node = malloc(sizeof(ll_node_t*));
new_node->data = malloc(list->data_size);
// err handle
memcpy(new_node->data, new_data, list->data_size);
if(n == 0 || list->size == 0) {
new_node->next = list->head;
list->head = new_node;
list->size++;
return;
}
if(n < list->size)
{
ll_node_t* current = list->head;
for(int i = 0; i < n - 1; i++)
{
current = current->next;
}
new_node->next = current->next;
current->next = new_node;
list->size++;
return;
}
if(n >= list->size)
{
ll_node_t* current = list->head;
for(unsigned int i = 0; i < list->size - 1; i++)
{
current = current->next;
}
new_node->next = current->next;
current->next = new_node;
list->size++;
return;
}
}
ll_node_t*
ll_remove_nth_node(linked_list_t* list, unsigned int n)
{
if(n < 0) exit(0);
ll_node_t* removedNode = NULL;
if(n == 0)
{
removedNode = list->head;
list->head = list->head->next;
list->size--;
return removedNode;
}
if(n < list->size)
{
ll_node_t* current = list->head;
// err handle
for(int i = 0; i < n - 1; i++)
{
current = current->next;
}
removedNode = current->next;
current->next = current->next->next;
list->size--;
return removedNode;
}
if(n >= list->size)
{
ll_node_t* current = list->head;
// err handle
for(int i = 0; i < n - 1; i++)
{
current = current->next;
}
removedNode = current->next;
current->next = NULL;
list->size--;
return removedNode;
}
}
unsigned int
ll_get_size(linked_list_t* list)
{
return list->size;
}
void
ll_free(linked_list_t** pp_list)
{
ll_node_t* current = (*pp_list)->head;
for(int i = 0; i < (*pp_list)->size; i++)
{
(*pp_list)->head = current->next;
free(current->data);
free(current);
current = (*pp_list)->head;
}
free(*pp_list);
}
void
ll_print_int(linked_list_t* list)
{
if(!list->size) exit(0);
ll_node_t* current = list->head;
for(int i = 0; i < list->size; i++)
{
printf("%d ", *(int*)current->data);
current = current->next;
}
printf("\n");
}
void
ll_print_string(linked_list_t* list)
{
if(!list->size) exit(0);
ll_node_t* current = list->head;
for(int i = 0; i < list->size; i++)
{
printf("%s ", (char*)current->data);
current = current->next;
}
printf("\n");
}
void partition(linked_list_t* list, int x)
{
ll_node_t* current = list->head;
ll_node_t* tail = list->head;
for(int i = 0; i < list->size; i++)
{
tail = tail->next;
}
//special case for the first element of the list
if(*(int*)current->data > x)
{
tail->next = current;
list->head = current->next;
tail = current;
}
// loop that finds elements > X
for(int i = 0; i < list->size - 1; i++)
{
if(*(int*)current->data > x)
{
// assigning the element to the end
tail->next = current->next;
// linking the previous element to the one after the element
current->next = current->next->next;
tail = tail->next;
tail->next = NULL;
// moving on to next element
current = current->next;
}
else current = current->next;
// moving on to next element
}
}
int main()
{
linked_list_t* linkedList;
while (1) {
char command[16];
long size, num;
scanf("%s", command);
if (strcmp(command, "list") == 0) {
linkedList = ll_create(sizeof(int));
scanf("%ld", &size);
long int curr_nr;
for (int i = 0; i < size; ++i) {
scanf("%ld", &curr_nr);
ll_add_nth_node(linkedList, size, &curr_nr);
}
}
if (strcmp(command, "X") == 0) {
scanf("%ld", &num);
partition(linkedList, num);
ll_print_int(linkedList);
break;
}
}
ll_free(&linkedList);
return 0;
}
so since i have list size as well, which is the number of elements in the list i thought the following:
before looping through the list, check if the head(first element) needs to be shifted at the end (if > X) and then have a loop that loops list->size - 1 times and when the condition inside is met, do the following:
it'd basically loop through elements and look at their next's, so when an element's next is > X, it would be shifted:
assign the tail's next element to be the element > X(current->next), then link current elements next to the one after the element. after that the new tail would be the element that was added at the end.
currently I get a Segmentation fault at the first line inside the condition in the for loop, on this line:
tail->next = current->next;
disclaimer: the main program, as i've tested it, works just fine for adding elements, and so on.
I going to offer an answer that is not exactly a solution to your existing code, but instead presents a different way of thinking about organizing your data as you work through it.
What if, instead of trying to reorder the list in place (managing head, current, and tail) while iterating through it, we deconstruct the list and construct two new lists? Our result becomes the concatenation of these two lists.
Visualized in pseudocode this would work like:
Q is [2 5 6 4 3 1]
part Q <= 3
L is []
R is []
Q eql [2 5 6 4 3 1]
^ -> L eql [2]
Q eql [5 6 4 3 1]
^ -> R eql [5]
Q eql [6 4 3 1]
^ -> R eql [5 6]
Q eql [4 3 1]
^ -> R eql [5 6 4]
Q eql [3 1]
^ -> L eql [2 3]
Q eql [1]
^ -> L eql [2 3 1]
Q eql []
Q is L concat R
Q eql [2 3 1 5 6 4]
By doing this, our partitioning function gets utilize the same logic we used to build our list in the first place.
Here is an example of what this might look like in C, using a very simple linked list:
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
struct node *next;
int value;
} node;
typedef struct {
node *head;
} list;
void list_append_node(list *l, node *n) {
node *root = l->head;
if (root) {
while (root->next)
root = root->next;
root->next = n;
} else
l->head = n;
}
void list_append_value(list *l, int v) {
node *n = calloc(1, sizeof *n);
n->value = v;
list_append_node(l, n);
}
void list_part(list *l, int v) {
list lower = { 0 };
list upper = { 0 };
for (node *curr = l->head, *temp; curr; curr = temp) {
temp = curr->next;
curr->next = NULL;
list_append_node(curr->value <= v ? &lower : &upper, curr);
}
list_append_node(&lower, upper.head);
l->head = lower.head;
}
int main(void) {
int inputs[] = { 2, 5, 6, 4, 3, 1 };
size_t len = sizeof inputs / sizeof *inputs;
list l = { 0 };
for (size_t i = 0; i < len; i++)
list_append_value(&l, inputs[i]);
list_part(&l, 3);
for (node *n = l.head, *t; n; n = t) {
t = n->next;
printf("%d ", n->value);
free(n);
}
putchar('\n');
}
stdout:
2 3 1 5 6 4
Note, the use of a node *tail member for each list could be implemented to improve the performance of list_append_node from O(N) to O(1).
I've been tasked with implementing Prim's algorithm to find the MCST using an adjacency matrix to represent the graph, and a struct to hold the MCST. The program takes in a file input, applies the algorithm and then outputs the minimum cost spanning tree. I got the program to take a file input and produce output, but the values I am getting are incorrect and look like dummy values to me.
My assumption is that the error occurs in either how I am storing the file input in my array, or in the algorithm itself. I've spent a good 12-15 hours troubleshooting this issue and am hoping someone can provide insight. The program is written in C and compiled with make in the format ./a6 <file>. I take and store the file input in my main() and then the methods are used in the order they are called. Below is an example my professor provided. The first line contains info about the vertices being entered and the remaining lines contain the actual data itself.
input:
6 10 0 <<--(size, edges, start)
0 1 16 <<--(from, to, weight)
0 5 21
0 4 19
1 2 5
1 3 6
1 5 11
2 3 10
3 4 18
3 5 14
4 5 33
output:
0 1 16 <<--(first edge)
1 2 5
1 3 6
1 5 11
3 4 18
total cost: 56
My code:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h> /* for INT_MAX */
#define N 10 /* max matrix size is 10 x 10 */
#define INF 9999
int cost = 0;
typedef struct lnode {
int fromv;
int tov;
int weight;
struct lnode *next;
} lnode;
int insertnode(lnode **lst, int from, int to, int wt);
void prims(int amtrx[][N],int n, lnode **lst);
void printpaths(lnode **lst);
void freelist(lnode **lst);
int isValid(int a, int b, int select[]);
int insertnode(lnode **lst, int from, int to, int wt){
lnode *newnode;
newnode = (lnode *) malloc(sizeof(struct lnode));
newnode->fromv = from;
newnode->tov = to;
newnode->weight = wt;
newnode->next=NULL;
if(*lst == NULL){
newnode -> next = *lst;
*lst = newnode;
} else {
lnode *current;
current = *lst;
while(current->next != NULL){
current = current->next;
}
newnode->next = current->next;
current->next = newnode;
}
return 1;
}
int isValid(int a, int b, int select[]){
if(a == b) return 0;
if(select[a] == 0 && select[b] == 0) return 0;
else if (select[a] == 1 && select[b] == 1) return 0;
return 1;
}
void prims(int amtrx[][N], int n, lnode **lst){
int i, j, row, col, edges_seen, min;
int select[N] = {0};
edges_seen = 0;
select[n] = 1;
while(edges_seen < N-1){
min = INF;
row = -1;
col = -1;
for(i = 0; i < N; i++) {
for(j = 0; j < N; j++){
if(amtrx[i][j] < min) {
if(isValid(i, j, select) == 1){
min = amtrx[i][j];
row = i;
col = j;
}
}
}
}
if(row != -1 && col != -1){
select[col] = 1;
select[row] = 1;
cost = cost + min;
insertnode(lst, row, col, min);
edges_seen++;
}
for(i = 0; i < N; i++){
printf("%3d", select[i]);
}
puts("\n\n");
}
}
void printpaths(lnode **lst){
lnode *current;
current = *lst;
while(current != NULL) {
printf("%4i ",current->fromv);
printf("%4i ", current->tov);
printf("%4i \n", current->weight);
current = current->next;
}
printf("\ntotal cost: %4i\n", cost);
}
void freelist(lnode **lst) {
lnode *temp = NULL;
while(*lst != NULL)
{
temp = *lst;
*lst = (*lst)->next;
free(temp);
}
}
int main(int argc, char **argv){
FILE *f = fopen(argv[1], "r");
lnode *lst;
lst = (lnode *)malloc(sizeof(struct lnode));
int i, j, nsz, nedg, fr, to, vtx, wt;
vtx = 1111;
nedg = 999;
nsz = 100;
fscanf(f, "%d %d %d", &nsz, &nedg, &vtx);
int amtrx[nsz][N];
for(i = 0; i < nsz; i++){
for(j = 0; j < nsz; j++){
amtrx[i][j] = INF;
}
}
for(i = 0; i < nedg; i++){
fscanf(f, "%d %d %d", &fr, &to, &wt);
amtrx[fr][to] = wt;
amtrx[to][fr] = wt;
}
fclose(f);
prims(amtrx, vtx, &lst);
printpaths(&lst);
freelist(&lst);
return EXIT_SUCCESS;
}
I dont have any experience with parallelism. So, if you could help me it would be really amazing.
I developed a code in C and this part of the code takes 99% of the execution time.
h is a linked list, a really long linked list.
g = h;
while(g != NULL){
f = g->next;
t = g;
while(f != NULL){
if(SomeFastBooleanFunction(g, f)){
fastMergeInformationsInG(g,f);
t->next = f->next;
free(f);
f = t->next;
}
else{
t = f;
f = f->next;
}
}
g = g->next;
}
The biggest problem here is the lenght of the linked list that is really big (approximated n!2^{binomial{n}{2}} and n >= 9). Any ideas are wellcome.
Thanks a lot.
------------ UPDATE -----------------
I will put here the real code used. The function above is the cleanIso bellow. I didn't put the checkIso funcion, but this function is a optimized function that check is f is isomorphic to g.
struct Graph{
SomeInfo
int *edges;
struct Graph *next;
};
graph *cleanIso(graph *g){
graph *f1, *f2, *f3;
f1 = g;
while(f1 != NULL){
f2 = f1;
f3 = f1->next;
while(f3 != NULL){
if(checkColorIso(f1, f3)){
f1->nHom += f3->nHom;
f2->next = f3->next;
free(f3->edges);
free(f3);
f3 = f2->next;
}
else{
f2 = f3;
f3 = f3->next;
}
}
f1 = f1->next;
}
return g;
}
int checkColorIso(graph *g, graph *f){
graph *h;
int r = 0;
int v[3] = {1, 2, 3};
int nP = g->size*(g->size - 1)/2;
int a[3], b[3];
//Initializing
a[0] = 0;
a[1] = 0;
a[2] = 0;
b[0] = 0;
b[1] = 0;
b[2] = 0;
//It just check if it there is some color bijection that maybe produce a isormophism
for(int i = 0; i < g->size*(g->size - 1)/2; i++){
a[g->edges[i]-1]++;
b[f->edges[i]-1]++;
}
do{
if(a[0] == b[v[0]-1] && a[1] == b[v[1]-1] && a[2] == b[v[2]-1]){
r++;
}
}while(std::next_permutation(v, v+3));
if(r == 0)
return 0;
r = 0;
h = initializeGraph(g->size, NULL);
do{
copyGraph(f, h);
for(int i = 0; i < nP; i++)
h->edges[i] = v[h->edges[i] - 1];
r = checkIso(g, h);
}while(std::next_permutation(v, v+3) && r == 0);
free(h->edges);
free(h);
return r;
}
I am trying to sort a linear linked list by last name, however it is crashing, also i don't know if my algorithm is working correctly.
Can someone help me to stop it from crashing, and see if my algorithm for sorting the list is working?
void sort(NODEPTR *employees, int maxEmployees)
{
int i = 0, j = 0, k = 0;
NODEPTR p, q, pTrail = NULL, qTrail, temp;
temp = (NODEPTR) calloc(1, sizeof(node));
qTrail = *employees;
q = (*employees)->next;
for (i = 0; i < maxEmployees; i++)
{
p = *employees;
while (p != q)
{
if (strcmp(p->lastName, q->lastName))
{
temp = q;
qTrail = q->next;
q = pTrail->next;
temp = pTrail->next;
pTrail = temp;
p = q;
}
else
{
pTrail = p;
p = p->next;
}
}
qTrail = q;
q = q->next;
pTrail = NULL;
}
printf("%10s %10ss\n", "First", "Last");
printf("%10s %10s\n", "-----", "----");
for (i = 0; i < maxEmployees; i++)
{
printf("%10s %10ss\n", (*employees)->firstName, (*employees)->lastName);
}
}
Linked List:
typedef struct node
{
char firstName[11];
char lastName[16];
char gender;
int tenure;
char rate;
float salary;
struct node *next;
} node, *NODEPTR;
Your logic seems to be wrong:
strcmp() will return three values.
1 if first argument's value is >
-1 if second argument's value is >
0 if both arguments's value are same.
So based on strcmp(p->lastName,q->lastName) you can not sort.
You should change the position only when strcmp() return 1. for -1 and 0 it should go in else part.
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).