использование qsort для сортировки указателей структур по разным переменным

Я пытаюсь понять qsort библиотеки c в контексте указателей на структуры. Вот существующий код, которым я хотел бы манипулировать:

Структура:

#define MAX_NAME 20
#define NUM_MONTHS 12

typedef struct EMP {
    char name[MAX_NAME+1];
    int monthSales[NUM_MONTHS];
    int total;
} Emp;

Глобальная инициализация данных и их размер:

Emp *data;//where all entries are kept
int empSize;

и я построил 2 массива указателей Emp, которые я хотел бы ссылаться на данные в разных порядках:

Emp *nameArray[empSize];//an array of pointers to point to entries alphabetically
Emp *salesArray[empSize]; //an array of pointers to pointing to entries by sales

после того, как они были одинаково назначены, я хотел бы использовать qsort, чтобы упорядочить их по-разному. nameArray в алфавитном порядке, используя имя в структуре и массив продаж от большего к меньшему, используя итог в структуре

Как должны выглядеть методы сравнения и аргументы qsort?

Спасибо


person jth41    schedule 23.03.2012    source источник
comment
это домашнее задание? Похоже, такой вопрос я мог бы задать, когда работал в сфере образования.   -  person gbulmer    schedule 24.03.2012
comment
Как выглядит ваш код, который пытается отсортировать один из массивов? Начали ли вы с массива Emp data[empSize];, чтобы немного упростить себе задачу? Я бы начал с массива структур, заработал, а затем использовал массив указателей. Затем напишите вторую функцию сравнения и используйте второй массив указателей.   -  person gbulmer    schedule 24.03.2012


Ответы (2)


Вам просто нужно определить две разные функции сравнения. Каждая функция сравнения должна принимать два указателя на void (в этом случае вы должны привести их к типам Emp **), а затем возвращать отрицательное целое число, ноль или положительное целое число, если первая запись меньше, равна или больше чем второй соответственно.

Для сортировки по сумме вы можете просто вычесть второе total из первого. Если первая сумма меньше второй, это приводит к отрицательному числу, и наоборот, когда первая сумма больше второй. Когда они равны, возвращается ноль.

int compareByTotal(const void *first, const void *second)
{
    int firstTotal = (*(Emp **)first)->total;
    int secondTotal = (*(Emp **)second)->total;

    return firstTotal - secondTotal;
}

Второй, поскольку это сравнение строк, может возвращать значение strcmp (которое подчиняется тем же соглашениям о возвращаемых значениях):

int compareByName(const void *first, const void *second)
{
    const char *firstName = (*(Emp **)first)->name;
    const char *secondName = (*(Emp **)second)->name;

    return strcmp(firstName, secondName);
}

Затем вы можете просто вызвать qsort, передав имена этих функций:

/* given: */
Emp *nameArray[empSize];//an array of pointers to point to entries alphabetically
Emp *salesArray[empSize]; //an array of pointers to pointing to entries by sales

/* use: */
qsort(nameArray, empSize, sizeof(*nameArray), &compareByName);
qsort(salesArray, empSize, sizeof(*salesArray), &compareByTotal);
person Platinum Azure    schedule 23.03.2012

Пример сортировки по именам:

#include <stdio.h>
#include <stdlib.h>
#define MAX_NAME 20
#define NUM_MONTHS 12

typedef struct EMP {
  char name[MAX_NAME + 1];
  int monthSales[NUM_MONTHS];
  int total;
} Emp;

int compareName(const void * a, const void * b)
{
  return (strcmp(((Emp*)a)->name, ((Emp*)b)->name));
}

int main()
{
  Emp *data;
  int empSize = 100;
  qsort(data, empSize, sizeof(Emp), compareName);
  // qsort(data, empSize, sizeof(Emp), compareSales);
  return 0;
}
person perreal    schedule 23.03.2012
comment
Почему вы используете sizeof(int) в качестве третьего аргумента для qsort()? - person Platinum Azure; 24.03.2012
comment
@PlatinumAzure, size: Size in bytes of each element in the array - person perreal; 24.03.2012
comment
Технически в вашем примере элементы Emps (даже не указатели на них), но в примере OP они Emp *s. Не гарантируется, что они будут того же размера, что и sizeof(int), особенно в 64-битной системе. Кроме того, в любом случае гораздо безопаснее просто использовать sizeof(*data). Таким образом, это более общий и ориентированный на будущее. - person Platinum Azure; 24.03.2012