如何对包含自定义(即用户定义的)对象的向量进行排序。 可能,应该使用标准的STL算法排序以及一个谓词(函数或函数对象),该谓词将对自定义对象中的一个字段(作为排序的键)进行操作。 我的思路对吗?
当前回答
您可以使用用户定义的比较器类。
class comparator
{
int x;
bool operator()( const comparator &m, const comparator &n )
{
return m.x<n.x;
}
}
其他回答
是的,std::sort()与第三个参数(函数或对象)将更容易。一个例子: http://www.cplusplus.com/reference/algorithm/sort/
对X类型的自定义对象的vector或任何其他适用(可变输入迭代器)范围进行排序可以使用各种方法来实现,特别是包括使用标准库算法,如
排序, stable_sort, partial_sort或 partial_sort_copy。
由于大多数获得X元素相对顺序的技术已经发布,我将从“为什么”和“何时”使用各种方法的一些注释开始。
“最佳”方法取决于不同的因素:
对X对象的范围进行排序是常见的还是罕见的任务(这样的范围会在程序中多个不同的地方进行排序还是由库用户进行排序)? 所需的排序是“自然的”(预期的)还是有多种方法可以将类型与自身进行比较? 性能是一个问题,还是X对象的排序范围应该是万无一失的?
如果对X的范围进行排序是一项常见任务,并且所实现的排序是预期的(即X只是包装了一个基本值),那么on可能会使用重载操作符<,因为它可以在没有任何模糊的情况下进行排序(如正确传递适当的比较器),并重复产生预期的结果。
如果排序是一项常见任务,或者在不同的上下文中可能需要,但有多个标准可用于排序X对象,我将使用函子(自定义类的重载operator()函数)或函数指针(即一个函子/函数用于词法排序,另一个用于自然排序)。
如果类型X的排序范围不常见或在其他上下文中不太可能,我倾向于使用lambdas,而不是用更多函数或类型使任何名称空间混乱。
如果排序在某种程度上不“清晰”或“自然”,这尤其正确。您可以很容易地了解排序背后的逻辑,因为lambda是就地应用的,而operator<一看就是opague,您必须查看定义才能知道将应用什么排序逻辑。
但是请注意,单个操作符<定义是单点故障,而多个lambas是多个故障点,需要更加谨慎。
如果操作符<的定义在排序完成/编译排序模板时不可用,编译器可能会在比较对象时强制进行函数调用,而不是内联排序逻辑,这可能是一个严重的缺陷(至少在没有应用链接时间优化/代码生成时)。
实现类X的可比性的方法,以便使用标准库排序算法
让std::vector<X> vec_X;and std::vector<Y> vec_Y;
1. 重载T::operator<(T)或operator<(T, T),并使用不需要比较函数的标准库模板。
重载成员运算符<:
struct X {
int i{};
bool operator<(X const &r) const { return i < r.i; }
};
// ...
std::sort(vec_X.begin(), vec_X.end());
或自由运算符<:
struct Y {
int j{};
};
bool operator<(Y const &l, Y const &r) { return l.j < r.j; }
// ...
std::sort(vec_Y.begin(), vec_Y.end());
2. 使用带有自定义比较函数的函数指针作为排序函数参数。
struct X {
int i{};
};
bool X_less(X const &l, X const &r) { return l.i < r.i; }
// ...
std::sort(vec_X.begin(), vec_X.end(), &X_less);
3.为可作为比较函子传递的自定义类型创建bool operator()(T, T)重载。
struct X {
int i{};
int j{};
};
struct less_X_i
{
bool operator()(X const &l, X const &r) const { return l.i < r.i; }
};
struct less_X_j
{
bool operator()(X const &l, X const &r) const { return l.j < r.j; }
};
// sort by i
std::sort(vec_X.begin(), vec_X.end(), less_X_i{});
// or sort by j
std::sort(vec_X.begin(), vec_X.end(), less_X_j{});
这些函数对象定义可以使用c++ 11和模板编写得更通用一些:
struct less_i
{
template<class T, class U>
bool operator()(T&& l, U&& r) const { return std::forward<T>(l).i < std::forward<U>(r).i; }
};
可用于对成员I支持<的任何类型进行排序。
4. 将一个匿名闭包(lambda)作为比较参数传递给排序函数。
struct X {
int i{}, j{};
};
std::sort(vec_X.begin(), vec_X.end(), [](X const &l, X const &r) { return l.i < r.i; });
c++ 14支持更通用的lambda表达式:
std::sort(a.begin(), a.end(), [](auto && l, auto && r) { return l.i < r.i; });
哪个可以被包装在宏中
#define COMPARATOR(code) [](auto && l, auto && r) -> bool { return code ; }
使普通比较器的创建相当顺利:
// sort by i
std::sort(v.begin(), v.end(), COMPARATOR(l.i < r.i));
// sort by j
std::sort(v.begin(), v.end(), COMPARATOR(l.j < r.j));
你的思路是对的。Std::sort默认使用操作符<作为比较函数。所以为了对对象排序,你要么重载bool操作符<(const T&, const T&),要么提供一个函数对象来进行比较,就像这样:
struct C {
int i;
static bool before( const C& c1, const C& c2 ) { return c1.i < c2.i; }
};
bool operator<( const C& c1, const C& c2 ) { return c1.i > c2.i; }
std::vector<C> values;
std::sort( values.begin(), values.end() ); // uses operator<
std::sort( values.begin(), values.end(), C::before );
使用函数对象的好处是可以使用函数访问类的私有成员。
在c++ 20中,可以默认操作符<=>,无需用户定义比较器。编译器会处理这些。
#include <iostream>
#include <compare>
#include <vector>
#include <algorithm>
struct MyInt
{
int value;
MyInt(int val) : value(val) {}
auto operator<=>(const MyInt& other) const = default;
};
int main()
{
MyInt Five(5);
MyInt Two(2);
MyInt Six(6);
std::vector V{Five, Two, Six};
std::sort(V.begin(), V.end());
for (const auto& element : V)
std::cout << element.value << std::endl;
}
输出:
2
5
6
typedef struct Freqamp{
double freq;
double amp;
}FREQAMP;
bool struct_cmp_by_freq(FREQAMP a, FREQAMP b)
{
return a.freq < b.freq;
}
main()
{
vector <FREQAMP> temp;
FREQAMP freqAMP;
freqAMP.freq = 330;
freqAMP.amp = 117.56;
temp.push_back(freqAMP);
freqAMP.freq = 450;
freqAMP.amp = 99.56;
temp.push_back(freqAMP);
freqAMP.freq = 110;
freqAMP.amp = 106.56;
temp.push_back(freqAMP);
sort(temp.begin(),temp.end(), struct_cmp_by_freq);
}
如果compare为false,它将执行“swap”。