Подтвердить что ты не робот

Сортировка, основанная на нескольких вещах в С++

struct Record
{
    char Surname[20];
    char Initial;
    unsigned short int Gender; //0 = male | 1 = female
    unsigned short int Age;
};
Record X[100];

Как я могу использовать Quicksort для сортировки значений в возрастающий возраст, с самками перед мужчинами и фамилиями в алфавитном порядке? У меня есть:

bool CompareData(const int& A, const int& B)
{
    return Records[A].Age < Records[B].Age; //this sorts by age atm
}
4b9b3361

Ответ 1

bool CompareData(const int& A, const int& B)
{
    return (Records[A].Age < Records[B].Age) ||
           ((Records[A].Age == Records[B].Age) && (Records[A].Gender > Records[B].Gender)) || 
           ((Records[A].Age == Records[B].Age) && (Records[A].Gender == Records[B].Gender) &&
              (strcmp(Records[A].Surname, Records[B].Surname) < 0));
}

Это сначала сравнивается по возрасту и возвращает true, если A должен появляться до B в зависимости от возраста.

Если возрасты равны, тогда он сравнивается по полу и возвращает true, если A должен появиться перед B на основе пола (A является женским, а B - мужчиной).

Если возрасты равны, а гендерные группы равны, тогда они сравниваются по фамилии (используя strcmp, хотя, если вы использовали std::string вместо массива char, вы могли бы просто использовать <) и возвращает true, если A должно появляться до B по алфавиту по фамилии.

Ответ 2

общий шаблон:

bool CompareData(const T& a, const T& b) 
{ 
   if (a.PrimaryCondition < b.PrimaryCondition) return true;
   if (b.PrimaryCondition < a.PrimaryCondition) return false;

   // a=b for primary condition, go to secondary
   if (a.SecondaryCondition < b.SecondaryCondition) return true;
   if (b.SecondaryCondition < a.SecondaryCondition) return false;

   // ...

   return false;
} 

где < указывает "меньше" в желаемом порядке сортировки, вам может потребоваться использовать для него пользовательские операции сравнения (например, strcmp для строк или изменить <, если вы хотите заказать нисходящий) (спасибо Гарри за это)

Я использовал < для всех условий, так как иногда доступна единственная операция сравнения, например. когда вам нужно использовать предикат сравнения неизвестного типа данных.

[править] Примечание: последняя строка return false обрабатывает случай, когда a и b считаются равными для компаратора.

Представьте a.PrimaryCondition==b.PrimaryCondition и a.SecondaryCondition==b.SecondaryCondition - в этом случае ни одно из предыдущих условий не возвращает никакого значения.

Ответ 3

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

например.

bool CompareAge (const record& l, const record& r)
{
  return l.age < r.age;
}

bool CompareGender (const record& l, const record& r)
{
  return l.gender < r.gender;
}

std::stable_sort(X, X+100, &CompareGender);
std::stable_sort(X, X+100, &CompareAge);

это будет потенциально немного медленнее, но позволит вам больше гибкости с порядком сортировки

Ответ 4

Лучше реализовать компаратор следующим образом:

bool CompareRecords(const Record& a, const Record& b)
{
    if (a.Age < b.Age)
        return true;
    else if (a.Age > b.Age)
        return false;

    if (a.Gender < b.Gender)
        return true;
    else if (a.Gender > b.Gender)
        return false;

    if (strcmp(a.Surname, b.Surname) < 0)
        return true;

    return false;
}

Это позволяет вам легко использовать алгоритм std::sort. Сортировка будет выглядеть следующим образом:

std::sort(X, X + 100, &CompareRecords);

ИЗМЕНИТЬ

Возможно, вы захотите реализовать operator < для этой структуры - в этом случае вы обычно можете сравнить два объекта структуры Record с оператором <. И тогда вам не нужно добавлять третий параметр в std::sort. И хорошо, с этим и реализованным operator == вы можете сделать все возможные сравнения.:)

Ответ 5

Простым решением на С++ является

struct Record {
    std::string Surname;
    char Initial;
    unsigned short int Gender; //0 = male | 1 = female
    unsigned short int Age;

    operator<(Record const& rhs) const {
        return std::tie(Gender, Age, Surname) < std::tie(rhs.Gender, rhs.Age, rhs.Surname);
};

Однако std::tie сортирует непосредственно по значениям поля. Это означает, что вы не можете использовать char[20], и самцы сортируют сначала. Простая вариация решает это:

struct Record {
    char Surname[20];
    char Initial;
    unsigned short int Gender; //0 = male | 1 = female
    unsigned short int Age;

    operator<(Record const& rhs) const {
        return std::make_tuple(~Gender, Age, std::string(Surname)) <
               std::make_tuple(~rhs.Gender, rhs.Age, std::string(rhs.Surname));
};

С make_tuple мы можем передавать выражения.