Writing a compare function for a structure for qsort?

半世苍凉 提交于 2019-12-24 03:46:07

问题


I'm having trouble writing a compare function for qsort function in C. This is what I currently have:

int cmpfunc(const void *a, const void *b) {
    return (*(Individual*)a->fitness - *(Individual*)b->fitness);
}

I know how the compare function works but I don't understand how to reference an integer value within my structure called Individual. Here is the structure of the Individual.

typedef struct {
    PPM_IMAGE image;
    double fitness;
} Individual;

I want to compare the fitness values within the structure.


回答1:


This part

*(Individual*)a->fitness

is wrong. You try to access fitness using -> but at the same time you dereference the pointer using *. You can't do both!

Here are two solutions.

Solution A: Dereference using * and access fitness using .

(*(Individual*)a).fitness

Solution B: Access fitness using ->

((Individual*)a)->fitness

Both solutions also requires a cast from void* to Individual*.

The same apply for variable b

If you are a beginner in C I'll recommend that you avoid using compact statements where multiple things happens. Instead split the compact statement into a number of individual statements. That will make the code easier to understand and debug. Like:

int cmpfunc (const void * a, const void * b){
    Individual* pA = a;
    Individual* pB = b;
    double fitnessA = pA->fitness;
    double fitnessB = pB->fitness;
    return fitnessA - fitnessB;
}

You don't need to worry about performance. The compiler will optimize the code to be just as efficient as the single statement code.

That said - as spotted by @chqrlie - notice that the compare code is wrong!

The function returns an integer but fitnessA - fitnessB is a double that will be converted to an integer. So 0.1 - 0.0 will end up returning 0 - which is not what you want.

You can see this answer https://stackoverflow.com/a/53466034/4386427 from @chqrlie for further details.

The code can also be changed like:

int cmpfunc (const void * a, const void * b){
    Individual* pA = a;
    Individual* pB = b;
    double fitnessA = pA->fitness;
    double fitnessB = pB->fitness;
    if (fitnessA > fitnessB) return 1;
    if (fitnessA < fitnessB) return -1;
    return 0;
}



回答2:


Assuming you call qsort with an array of Individual structures, you should cast the arguments received by the compare function as pointers to Individual structures, preferably const Individual * to avoid warnings.

You can then compare the fitness members and return an ordering value. Note that you cannot just return the difference of the values as these may be non integral and the difference may even overflow the range of type int.

Here is a classic way to do this:

int cmpfunc(const void *a, const void *b) {
    const Individual *aa = a;
    const Individual *bb = b;
    /* return -1, 0 or 1 depending on the comparison results */
    return (aa->fitness > bb->fitness) - (aa->fitness < bb->fitness);
}


来源:https://stackoverflow.com/questions/53465147/writing-a-compare-function-for-a-structure-for-qsort

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!