Reputation: 47
I'm currently implementing some algorithm on graphs and I use a struct to keep the information about every edge in the graph: its source vertex, its destination vertex and its weight.
I have my struct declared as following:
typedef struct edge {
int data[3]; //src, dest, weight
} edge_t, *edge_p;
Then I create a variable pointer and allocate memory for n
structs, where n
is a number of edges in a graph:
edge_p localEdges = (edge_p)malloc(n*sizeof(edge_t));
Then I fill up struct localEdges
with the values of another struct allEdges
of the same type:
for (int i = 0; i < num_edges; i++) {
localEdges[i].data[0] = allEdges[i].data[0];
localEdges[i].data[1] = allEdges[i].data[1];
localEdges[i].data[2] = allEdges[i].data[2];
}
And then I need to sort the contents of localEdges
by ascending order of data[2] field (by ascending edge weight). My compare function is this:
int myComp (const void *a, const void *b)
{
const edge_t * ptr_a = (const edge_t *)a;
const edge_t * ptr_b = (const edge_t *)b;
return ptr_b->data[2] < ptr_a->data[2];
}
And the call for the function is the following:
qsort(localEdges, n, sizeof(edge_t), myComp);
However, that doesn't work. The processed localEdges
array has some data placed wrongly. For example:
localEdges[0].data[2] = 1
localEdges[1].data[2] = 2
localEdges[2].data[2] = 1
localEdges[3].data[2] = 2
localEdges[4].data[2] = 3
localEdges[5].data[2] = 3
localEdges[6].data[2] = 4
When it should be:
localEdges[0].data[2] = 1
localEdges[1].data[2] = 1
localEdges[2].data[2] = 2
localEdges[3].data[2] = 2
localEdges[4].data[2] = 3
localEdges[5].data[2] = 3
localEdges[6].data[2] = 4
I guess there is something with pointers, but I'm not quite confident with them.
Any suggestions? I'll Appreciate your help.
Upvotes: 1
Views: 313
Reputation: 5369
It seems your comparer function is incorrectly implemented. It never returns negative result, just bool value (comparison operation) converted to 0 and 1. Could you try something like that:
int myComp (const void *a, const void *b)
{
const edge_t * ptr_a = (const edge_t *)a;
const edge_t * ptr_b = (const edge_t *)b;
return (ptr_b->data[2] < ptr_a->data[2]) ? -1 :
(ptr_b->data[2] > ptr_a->data[2]) ? 1 : 0;
}
Upvotes: 0
Reputation:
In short: Your comparison function is wrong. Citing a qsort()
manual:
The comparison function must return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second. If two members compare as equal, their order in the sorted array is undefined.
So, if you're returning 0
, the two elements are considered equal.
return ptr_b->data[2] < ptr_a->data[2];
This line does return 0
if the value in *ptr_b
is greater than that in *ptr_a
.
The correct way to do it is as follows:
int myComp (const void *a, const void *b)
{
const edge_t * ptr_a = (const edge_t *)a;
const edge_t * ptr_b = (const edge_t *)b;
if (ptr_a->data[2] < ptr_b->data[2]) return -1;
if (ptr_a->data[2] > ptr_b->data[2]) return 1;
return 0;
}
Upvotes: 3
Reputation: 310980
From the C Standard (7.22.5.2 The qsort function)
3 The contents of the array are sorted into ascending order according to a comparison function pointed to by compar, which is called with two arguments that point to the objects being compared. The function shall return an integer less than, equal to, or greater than zero if the first argument is considered to be respectively less than, equal to, or greater than the second.
Thus define the function for example the following way
int myComp (const void *a, const void *b)
{
const edge_t * ptr_a = (const edge_t *)a;
const edge_t * ptr_b = (const edge_t *)b;
return ( ptr_b->data[2] < ptr_a->data[2] ) - ( ptr_a->data[2] < ptr_b->data[2] );
}
Upvotes: 2