Как можно сортировать вектор, содержащий пользовательские (то есть определяемые пользователем) объекты?
Вероятно, следует использовать стандартный алгоритм STL для сортировки вместе с предикатом (функцией или объектом функции), который будет работать с одним из полей (в качестве ключа для сортировки) в пользовательском объекте.
Я на правильном пути?
249
Ответы:
Простой пример использования
std::sort
Изменить: Как отметил Кирилл В. Лядвинский, вместо предоставления предиката сортировки, вы можете реализовать
operator<
дляMyStruct
:Использование этого метода означает, что вы можете просто отсортировать вектор следующим образом:
Edit2: Как предполагает Kappa, вы также можете сортировать вектор в порядке убывания, перегружая
>
оператор и немного меняя вызов сортировки:И вы должны назвать сортировку как:
источник
std::sort(vec.begin(), vec.end(), greater<MyStruct>())
который является чистым и элегантным.#include <functional>
использовать "std :: большее".operator<
и использовать либоstd::sort(vec.begin(), vec.end());
или вstd::sort(vec.rbegin(), vec.rend());
зависимости от того, хотите ли вы иметь восходящий или нисходящий порядок.В интересах освещения. Я выдвинул реализацию, используя лямбда-выражения .
C ++ 11
C ++ 14
источник
>
вместо того,<
чтобы получить в порядке убывания.Вы можете использовать функтор в качестве третьего аргумента
std::sort
или вы можете определитьoperator<
в своем классе.источник
const
в конце подпись функции?const
.const
Ключевое слово в конце подписи указывает, чтоoperator()
функция не изменяет экземплярXgreater
структуры (которая обычно может иметь переменные-члены), тогда как указаниеconst
для входных значений только указывает, что эти входные значения являются неизменяемыми.Сортировка такого
vector
или любого другого применимого (изменяемого входного итератора) диапазона пользовательских объектов типаX
может быть достигнута с использованием различных методов, особенно включая использование стандартных библиотечных алгоритмов, таких какsort
,stable_sort
,partial_sort
илиpartial_sort_copy
,Поскольку большинство методов для получения относительного упорядочения
X
элементов уже опубликованы, я начну с некоторых заметок о том, «почему» и «когда» использовать различные подходы.«Лучший» подход будет зависеть от разных факторов:
X
объектов общей или редкой задачей (будут ли эти диапазоны сортироваться в нескольких разных местах в программе или пользователями библиотеки)?X
объектов должны быть надежными?Если сортировка диапазонов
X
является распространенной задачей, и ожидаемая сортировка должна ожидаться (то есть,X
просто оборачивает одно фундаментальное значение), то, вероятно, будет идти на перегрузкуoperator<
так как она позволяет сортировку без какого-либо размытия (например, правильную передачу соответствующих компараторов) и многократно дает ожидаемую полученные результаты.Если сортировка является распространенной задачей или, вероятно, потребуется в разных контекстах, но есть несколько критериев, которые можно использовать для сортировки
X
объектов, я бы выбрал Functors (перегруженныеoperator()
функции пользовательских классов) или указатели на функции (т.е. один функтор / функция для лексического упорядочения и еще один для естественного упорядочения).Если сортировка диапазонов типов
X
необычна или маловероятна в других контекстах, я склонен использовать лямбды вместо того, чтобы загромождать любое пространство имен большим количеством функций или типов.Это особенно верно, если сортировка не является «чистой» или «естественной» в некотором роде. Вы можете легко понять логику упорядочения, если посмотреть на лямбду, которая применяется на месте, тогда как
operator<
на первый взгляд она непрозрачна, и вам придется поискать определение, чтобы знать, какая логика упорядочения будет применяться.Однако обратите внимание, что одно
operator<
определение - это одна точка отказа, тогда как несколько лямб - это несколько точек отказа и требуют большей осторожности.Если определение
operator<
где недоступно, где сортировка выполнена / шаблон сортировки скомпилирован, компилятор может быть вынужден сделать вызов функции при сравнении объектов, вместо того, чтобы включать логику упорядочения, которая может быть серьезным недостатком (по крайней мере, когда оптимизация времени соединения / генерация кода не применяется).Способы достижения сопоставимости
class X
для использования стандартных алгоритмов сортировки библиотекиПусть
std::vector<X> vec_X;
иstd::vector<Y> vec_Y;
1. Перегрузите
T::operator<(T)
илиoperator<(T, T)
и используйте стандартные библиотечные шаблоны, которые не ожидают функции сравнения.Либо элемент перегрузки
operator<
:или бесплатно
operator<
:2. Используйте указатель функции с пользовательской функцией сравнения в качестве параметра функции сортировки.
3. Создайте
bool operator()(T, T)
перегрузку для пользовательского типа, которая может быть передана как функтор сравнения.Эти определения функциональных объектов могут быть написаны немного более обобщенно, используя C ++ 11 и шаблоны:
который может быть использован для сортировки любого типа с
i
поддержкой членов<
.4. Передайте анонимное закрытие (лямбда) в качестве параметра сравнения в функции сортировки.
Где C ++ 14 обеспечивает еще более общее лямбда-выражение:
который можно обернуть в макрос
сделать обычное создание компаратора довольно плавным:
источник
bool X_less(X const &l, X const &r) const { return l.i < r.i; }
для компаратора, ноconst
ключевые слова должны быть удалены (так как это не функция-член).std::sort
или похож, но нужен экземплярCompare
, например, при создании экземпляраstd::set
?template<class T, class C> std::set<T, C> make_set(C const& compare) { return std::set<T, C>{ compare }; }
который можно использовать какauto xset = make_set<X>([](auto && l, auto && r) { return l.i < r.i; });
.Ты на правильном пути.
std::sort
будет использовать вoperator<
качестве функции сравнения по умолчанию. Таким образом, для сортировки ваших объектов вам придется либо перегружать,bool operator<( const T&, const T& )
либо предоставлять функтор, который выполняет сравнение, примерно так:Преимущество использования функтора заключается в том, что вы можете использовать функцию с доступом к закрытым членам класса.
источник
operator<
член класса (или структуры), потому что глобальный может использовать защищенные или закрытые члены. Или вы должны сделать это другом структуры С.Мне было любопытно, есть ли какое-либо измеримое влияние на производительность между различными способами вызова std :: sort, поэтому я создал этот простой тест:
Он создает случайный вектор, а затем измеряет, сколько времени требуется для его копирования и сортировки (и вычисления некоторой контрольной суммы, чтобы избежать слишком энергичного удаления мертвого кода).
Я компилировал с g ++ (GCC) 7.2.1 20170829 (Red Hat 7.2.1-1)
Вот результаты:
Похоже, что все параметры, за исключением передачи указателя на функцию, очень похожи, а передача указателя на функцию вызывает штраф + 30%.
Кроме того, похоже, что оператор <версия работает на ~ 1% медленнее (я повторил тест несколько раз, и эффект сохраняется), что немного странно, так как предполагает, что сгенерированный код отличается (мне не хватает навыков для анализа --save- вывод временных данных).
источник
Да,
std::sort()
с третьим параметром (функцией или объектом) было бы проще. Пример: http://www.cplusplus.com/reference/algorithm/sort/источник
В вашем классе вы можете перегрузить оператор "<".
источник
Ниже приведен код с использованием лямбды
источник
источник
Вы можете использовать пользовательский класс компаратора.
источник
Для сортировки вектора вы можете использовать алгоритм sort ().
Третий используемый параметр может быть больше или меньше, или также может использоваться любая функция или объект. Однако оператор по умолчанию - <, если вы оставите третий параметр пустым.
источник
если сравнение ложно, это сделает "обмен".
источник