Почему массив qsort int в порядке убывания неверен? - PullRequest
0 голосов
/ 14 апреля 2019

Я попытался написать функцию сравнения для qsorting массива int.И это дает правильные результаты по возрастанию.Но неверно по убыванию.Зачем?Какая будет правильная функция сравнения int?

int compare(const void *a, const void *b){
    int x = *(int*)a;
    int y = *(int*)b;
    return (x > y) - (x < y);
}

int reverse(const void *a, const void *b){
    return -compare(a, b);
}

int main(){
    int x[] = {500, 456, 18, 13, 3, 89, 800, 6874};
    qsort(x, sizeof(x[0]), sizeof(x)/sizeof(x[0]), reverse);
    for (int i=0; i < sizeof(x)/sizeof(x[0]); i++){
    printf("%d\n", x[i]);

    return 0;
}

Я ожидал убывания печатных целых чисел от самых больших 6874 до самых маленьких 3. Но я получил вместо этого:

800 6874 500 456 18 13 389

Ответы [ 2 ]

4 голосов
/ 14 апреля 2019

Вы поменяли местами второй и третий аргументы qsort - должно быть

qsort(x, sizeof(x)/sizeof(x[0]), sizeof(x[0]), reverse);

То, как вы его называете, поскольку ваш массив состоит из 8 элементов, а sizeof (int) на вашем компьютере равен 4, он сортирует пары целых чисел на основе первого целого в каждой паре.

0 голосов
/ 15 апреля 2019

Прежде чем заняться другими аспектами, вы переключили второй и третий параметры на qsort(3), первый - указатель массива, второй - число элементов, третий размер и четвертый - указатель функции сравнения.Чтобы получить хороший qsort(3), вам сначала нужно поместить параметры в правильном порядке :).

Ну, функция compare() должна возвращать < 0 (не -1), если a меньшечем b, > 0 (а не +1), если a больше, чем b, и ноль, если a и b равны.Ваша формула правильная, но немного слишком сложное выражение для чего-то, что может быть достигнуто простым вычитанием обоих параметров.Если вы проверите, что возвращают многие реализации strcpy(3) (ну, не все, но многие), это разница между символами в позиции, в которой обе строки различаются, что достаточно для эффективной реализации.

ByКстати, вы знаете, что void * - это указатель, совместимый с любым другим типом указателя, поэтому один из лучших способов написать функцию сравнения (основанную на ссылках на целые числа, а не на их значениях) - написать ее так:

int compare(int *a, int *b) 
{
    return *a - *b;
}

int reverse_compare(int *a, int *b) 
{
    return -compare(a, b);
}

(вы получите ложное предупреждение при вызове qsort(3)) или, что еще проще,

int reverse_compare(int *a, int *b) 
{
    return compare(b, a);
}

и передадите его непосредственно qsort(3).Действительно, для обратного сравнения требуются только два указателя, и его можно сделать полностью общим, написав его следующим образом:

int reverse_compare(const void *a, const void *b)
{
    return compare(b, a);
}

pru.c

Если вы проверите следующий пример, выобратите внимание, что reverse - это процедура, переданная в qsort (нет предупреждений при совпадении параметров и нет предупреждений внутри тела reverse при преобразовании их в void * при вызове в compare_int.)

#include <stdlib.h>
#include <stdio.h>

int compare_int(const int *a, const int *b)
{
    return (*a > *b) - (*b > *a);
}

int reverse(const void *a, const void *b)
{
    return compare_int(b, a);
}

int main()
{
    int x[] = {500, 456, 18, 13, 3, 89, 800,
        6874};
    qsort(x,
        sizeof(x)/sizeof(x[0]),
        sizeof(x[0]),
        reverse);
    for (int i=0; i <
            sizeof(x)/sizeof(x[0]); i++) {
        printf("%d\n", x[i]);
    }

    return 0;
}
...