Написание функции сравнения для структуры для qsort? - PullRequest
0 голосов
/ 25 ноября 2018

У меня проблемы с написанием функции сравнения для qsort функции на C. Это то, что у меня сейчас есть:

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

Я знаю, как работает функция сравнения, но я не понимаю, какдля ссылки на целочисленное значение в моей структуре под названием Individual.Вот структура Индивидуума.

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

Я хочу сравнить значения пригодности в структуре.

Ответы [ 2 ]

0 голосов
/ 25 ноября 2018

Предполагая, что вы вызываете qsort с массивом Individual структур, вы должны привести аргументы, полученные функцией сравнения, в качестве указателей к Individual структурам, предпочтительно const Individual *, чтобы избежать предупреждений.

Затем вы можете сравнить fitness членов и вернуть значение заказа.Обратите внимание, что вы не можете просто вернуть разницу значений, поскольку они могут быть нецелыми, и разница может даже выйти за пределы диапазона типа int.

Вот классический способ сделать это:

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);
}
0 голосов
/ 25 ноября 2018

Эта часть

*(Individual*)a->fitness

неверна.Вы пытаетесь получить доступ к fitness, используя ->, но в то же время вы разыменовываете указатель, используя *.Вы не можете сделать оба!

Вот два решения.

Решение A: Разыменование с использованием * и доступ к fitness с использованием .

(*(Individual*)a).fitness

Решение B: Доступ к fitness с использованием ->

((Individual*)a)->fitness

Для обоих решений также требуется приведение от void* до Individual*.

То же самое относится к переменной b

Если вы новичок в C, я бы порекомендовал вам избегать использования компактных выражений, где происходит множество вещей.Вместо этого разбейте компактное утверждение на ряд отдельных утверждений.Это облегчит понимание и отладку кода.Например:

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;
}

Вам не нужно беспокоиться о производительности.Компилятор оптимизирует код так, чтобы он был так же эффективен, как и код одного оператора.

При этом - как заметил @chqrlie - обратите внимание, что код сравнения неверен!

Функция возвращает целое число, но fitnessA - fitnessB - это двойное число, которое будет преобразовано в целое число.Так что 0.1 - 0.0 в конечном итоге вернет 0 - это не то, что вам нужно.

Вы можете увидеть этот ответ https://stackoverflow.com/a/53466034/4386427 от @chqrlie для получения дополнительной информации.

код также можно изменить, например:

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;
}
...