Сортировка, основанная на нескольких вещах в С++
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
}
Ответы
Ответ 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
мы можем передавать выражения.