Написание функции сравнения для структуры для qsort?

У меня возникли проблемы с написанием функции сравнения для функции 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;

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


person Akila Kavisinghe    schedule 25.11.2018    source источник
comment
@kiner_shah Хотя связанное сравнение верно для некоторых типов сравнения с плавающей запятой, здесь оно не применяется.   -  person 4386427    schedule 25.11.2018
comment
@kiner_shah Вы предоставили ссылку на функцию сравнения, которая не имеет отношения к этому вопросу.   -  person 4386427    schedule 25.11.2018


Ответы (2)


Эта часть

*(Individual*)a->fitness

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

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

Решение А. Разыменование с помощью * и доступ к fitness с помощью .

(*(Individual*)a).fitness

Решение Б. Получите доступ к 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;
}
person 4386427    schedule 25.11.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);
}
person chqrlie    schedule 25.11.2018