The useful qsort function
Why to write a new complex and maybe inefficient function for sorting arrays (of any type), if we can use qsort? Honestly i didn’t knew about the existence of this until i learned it in the Programming Workshop, and i was amazed of how easy it was and how useful it can be.
You can find the documentation anywhere (man qsort if you are in linux), so i’ll show you some examples and how you can use this function.
void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) );
that’s the function signature, it may look strange, but isn’t hard at all.
As you can see the presence of void*, tell us that it can sort any kind of arrays (int, char, struct arrays), same with the compare function.
The first argument is a pointer to the first element of the array, the second is the number of elements that the array has, the third argument is the size of each of the elements of the array (e.g. sizeof(array[0])), and the last one is the compare function, i’ll talk about that now.
The compare function must have the following signature:
int comparator ( const void * elem1, const void * elem2 );
As i told you before, that allow us to use any data type, since it receives as parameters two pointers to elements type-casted as void*. You should then cast the parameters to some data type and compare them. The function should return negative is elem1 < elem2, positive if elem1 > elem2 or zero if elem1 == elem2 (obviously based on the criteria you used in the compare function).
Consider this simple example:
int compare(const void* a, const void* b)
{
return *(char*)a - *(char*)b;
}
So if we want to compare elements in a string, the two parameters will be pointer to an element, that means, a char* pointer. That’s way we have to cast the pointers that initially are passed as void* to char* (i.e (char*)a ), then we are able to reach the value of the element by using the * operand, so as you might see if the value of a is greater than b function will return a positive number, and so on if it is less or equal than b.
char wordA[100];
/*get data into wordA*/
qsort(wordA,strlen(wordA),sizeof(wordA[0]),compare)
/*now wordA is sorted in ascending order*/
You obviously can do the same with an array of numbers, just change the casts to int*.
Multi field sorting
Now, what if we want to sort a structure with several fields, and we have many criteria, with different priorities??
Lets take the following example (based on Contest scoreboard problem).
We have to output the teams sorted by their score, and the score is equal to the problems that each team has solved, but if two teams have the same score, then the submit time is considered, including the penalties for getting Wrong Answers. If still two teams have the same time, they are displayed based on their team number.
So we have here three criteria with different priorities:
- Number of solved problems.
- Total time (including penalties).
- Team number.
It isn’t trivial to make this kind of sorting without qsort, we might have to go through the array several time to make sure that we have considered the three criteria.
With qsort is easy, you just need to consider this in the compare function, and qsort will do the rest.
Lets assume our structure is:
struct PtjeTotal{
int eq;
int probs;
int time;
};
So we have eq (team number), probs (number of solved problems) and time (total time with penalties), and we want to sort an array already fill with data with the criteria we discuss before.
All that you need is:
int comparaDatos(const void *equipoA,const void *equipoB)
{
struct PtjeTotal *A = (struct PtjeTotal *) equipoA;
struct PtjeTotal *B = (struct PtjeTotal *) equipoB;
.
if( A->probs > B->probs)return 1; /*first criteria, number of solved problems*/
else if(B->probs > A->probs)return -1;
.
if(A->time time )return 1;/*second criteria, total time*/
else if( B->time time )return -1;
.
if(A->eq eq )return 1;/*third criteria, team number*/
else if(B->eq eq)return -1;
.
return 0; /*they are exactly equal*/
}
the dots are not part of the code, i had problems trying to make a blank line inside a code tag
That’s all!, as you can see, first we compare the number of solved problems, if they are equal nothing will be returned yet, so it moves into the next if-else, and again we compare, but this time the total time, if they are still equal nothing will be returned and we move into the last if-else, were we check the team number, they probably will be different (depending on problem statement), so it will return who is the greater based on the three criteria, or zero if they are exactly equals.
As we had seen, you can have different compare functions for sorting in many ways, or a compare function that sort a structure based on different criteria, this is very useful, and make thing a lot simpler than programming all this stuff by your own.