Answers:
一个简单的例子使用 std::sort
struct MyStruct
{
int key;
std::string stringValue;
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
};
struct less_than_key
{
inline bool operator() (const MyStruct& struct1, const MyStruct& struct2)
{
return (struct1.key < struct2.key);
}
};
std::vector < MyStruct > vec;
vec.push_back(MyStruct(4, "test"));
vec.push_back(MyStruct(3, "a"));
vec.push_back(MyStruct(2, "is"));
vec.push_back(MyStruct(1, "this"));
std::sort(vec.begin(), vec.end(), less_than_key());
编辑:作为基里尔五Lyadvinsky指出,而不是提供一个排序谓词,您可以实现operator<
的MyStruct
:
struct MyStruct
{
int key;
std::string stringValue;
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
bool operator < (const MyStruct& str) const
{
return (key < str.key);
}
};
使用此方法意味着您可以简单地对向量进行如下排序:
std::sort(vec.begin(), vec.end());
Edit2:正如Kappa建议的那样,您还可以通过重载>
运算符并稍微改变sort的调用来对向量进行降序排序:
struct MyStruct
{
int key;
std::string stringValue;
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
bool operator > (const MyStruct& str) const
{
return (key > str.key);
}
};
您应该将sort称为:
std::sort(vec.begin(), vec.end(),greater<MyStruct>());
std::sort(vec.begin(), vec.end(), greater<MyStruct>())
干净而优雅。
#include <functional>
使用“ std :: greater”。
operator<
使用std::sort(vec.begin(), vec.end());
或使用的位置,或者std::sort(vec.rbegin(), vec.rend());
取决于您要使用升序还是降序。
为了覆盖。我提出了一个使用lambda表达式的实现。
C ++ 11
#include <vector>
#include <algorithm>
using namespace std;
vector< MyStruct > values;
sort( values.begin( ), values.end( ), [ ]( const MyStruct& lhs, const MyStruct& rhs )
{
return lhs.key < rhs.key;
});
C ++ 14
#include <vector>
#include <algorithm>
using namespace std;
vector< MyStruct > values;
sort( values.begin( ), values.end( ), [ ]( const auto& lhs, const auto& rhs )
{
return lhs.key < rhs.key;
});
>
而不是<
获取降序。
您可以将functor用作的第三个参数std::sort
,也可以operator<
在类中定义。
struct X {
int x;
bool operator<( const X& val ) const {
return x < val.x;
}
};
struct Xgreater
{
bool operator()( const X& lx, const X& rx ) const {
return lx.x < rx.x;
}
};
int main () {
std::vector<X> my_vec;
// use X::operator< by default
std::sort( my_vec.begin(), my_vec.end() );
// use functor
std::sort( my_vec.begin(), my_vec.end(), Xgreater() );
}
const
在函数签名的末尾添加?
const
。
const
签名末尾的关键字指定该operator()
函数不更改该Xgreater
结构的实例(通常可以具有成员变量),而const
对于输入值指示仅指定那些输入值是不可变的。
可以使用多种方法来实现vector
对此类自定义对象或任何其他适用的(可变输入迭代器)范围进行排序X
,特别是包括使用标准库算法(例如
由于X
已经获得了大多数用于获取元素相对顺序的技术,因此,我将以“为什么”和“何时”使用一些方法开始一些注释。
“最佳”方法将取决于不同的因素:
X
对象的范围进行排序是常见的还是罕见的任务(将这些范围在程序中还是在库用户的不同位置进行排序)?X
对象分类范围应该万无一失?如果的排序范围X
是一项常见的任务,并且期望实现的排序(即X
仅包装一个基本值),则可能会导致过载,operator<
因为它可以进行排序而没有任何绒毛(例如正确地传递了适当的比较器),并且可以反复产生预期的结果结果。
如果排序是一项常见的任务,或者可能需要在不同的上下文中进行,但是有多个可用于对X
对象进行排序的条件,则可以使用Functors(operator()
自定义类的重载函数)或Function指针(例如,一个functor / function)用于词法排序,另一种用于自然排序)。
如果类型的排序范围X
在其他情况下不常见或不太可能,我倾向于使用lambda而不是使具有更多函数或类型的任何名称空间变得混乱。
如果排序在某种程度上不是“清晰的”或“自然的”,则尤其如此。当您查看就地应用的lambda时,可以很容易地获得排序背后的逻辑,而operator<
乍一看却很模糊,您必须向上看定义才能知道将应用什么排序逻辑。
但是请注意,单个operator<
定义是单个故障点,而多个lambas是多个故障点,需要更加谨慎。
如果operator<
在进行排序/编译排序模板的地方不存在的定义,则在比较对象时可能会迫使编译器进行函数调用,而不是内联排序逻辑,这可能会带来严重的缺点(至少在链接时间优化/代码生成未应用)。
class X
使用标准库排序算法实现可比性的方法让std::vector<X> vec_X;
和std::vector<Y> vec_Y;
T::operator<(T)
或operator<(T, T)
使用不希望具有比较功能的标准库模板。任一重载成员operator<
:
struct X {
int i{};
bool operator<(X const &r) const { return i < r.i; }
};
// ...
std::sort(vec_X.begin(), vec_X.end());
或免费operator<
:
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());
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);
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
支持下可用于对任何类型进行排序<
。
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));
bool X_less(X const &l, X const &r) const { return l.i < r.i; }
为比较器编写了代码,但const
应删除关键字(因为它不是成员函数)。
std::sort
或类似但需要实例化时Compare
(例如,当实例化std::set
?时)如何使用(4.)lambda方法?
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& )
或提供一个执行比较的函子,就像这样:
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 );
使用函子的优点是您可以使用具有访问类的私有成员权限的函数。
operator<
一个类(或结构)的成员,因为全局成员可以使用受保护的成员或私有成员。或者,你应该让结构下的一个朋友
我很好奇是否可以调用std :: sort的各种方式之间的性能受到可衡量的影响,所以我创建了这个简单的测试:
$ cat sort.cpp
#include<algorithm>
#include<iostream>
#include<vector>
#include<chrono>
#define COMPILER_BARRIER() asm volatile("" ::: "memory");
typedef unsigned long int ulint;
using namespace std;
struct S {
int x;
int y;
};
#define BODY { return s1.x*s2.y < s2.x*s1.y; }
bool operator<( const S& s1, const S& s2 ) BODY
bool Sgreater_func( const S& s1, const S& s2 ) BODY
struct Sgreater {
bool operator()( const S& s1, const S& s2 ) const BODY
};
void sort_by_operator(vector<S> & v){
sort(v.begin(), v.end());
}
void sort_by_lambda(vector<S> & v){
sort(v.begin(), v.end(), []( const S& s1, const S& s2 ) BODY );
}
void sort_by_functor(vector<S> &v){
sort(v.begin(), v.end(), Sgreater());
}
void sort_by_function(vector<S> &v){
sort(v.begin(), v.end(), &Sgreater_func);
}
const int N = 10000000;
vector<S> random_vector;
ulint run(void foo(vector<S> &v)){
vector<S> tmp(random_vector);
foo(tmp);
ulint checksum = 0;
for(int i=0;i<tmp.size();++i){
checksum += i *tmp[i].x ^ tmp[i].y;
}
return checksum;
}
void measure(void foo(vector<S> & v)){
ulint check_sum = 0;
// warm up
const int WARMUP_ROUNDS = 3;
const int TEST_ROUNDS = 10;
for(int t=WARMUP_ROUNDS;t--;){
COMPILER_BARRIER();
check_sum += run(foo);
COMPILER_BARRIER();
}
for(int t=TEST_ROUNDS;t--;){
COMPILER_BARRIER();
auto start = std::chrono::high_resolution_clock::now();
COMPILER_BARRIER();
check_sum += run(foo);
COMPILER_BARRIER();
auto end = std::chrono::high_resolution_clock::now();
COMPILER_BARRIER();
auto duration_ns = std::chrono::duration_cast<std::chrono::duration<double>>(end - start).count();
cout << "Took " << duration_ns << "s to complete round" << endl;
}
cout << "Checksum: " << check_sum << endl;
}
#define M(x) \
cout << "Measure " #x " on " << N << " items:" << endl;\
measure(x);
int main(){
random_vector.reserve(N);
for(int i=0;i<N;++i){
random_vector.push_back(S{rand(), rand()});
}
M(sort_by_operator);
M(sort_by_lambda);
M(sort_by_functor);
M(sort_by_function);
return 0;
}
它的作用是创建一个随机向量,然后测量复制它并对其副本进行排序需要多少时间(并计算一些校验和,以避免过强的死代码消除)。
我正在使用g ++(GCC)7.2.1 20170829(Red Hat 7.2.1-1)进行编译
$ g++ -O2 -o sort sort.cpp && ./sort
结果如下:
Measure sort_by_operator on 10000000 items:
Took 0.994285s to complete round
Took 0.990162s to complete round
Took 0.992103s to complete round
Took 0.989638s to complete round
Took 0.98105s to complete round
Took 0.991913s to complete round
Took 0.992176s to complete round
Took 0.981706s to complete round
Took 0.99021s to complete round
Took 0.988841s to complete round
Checksum: 18446656212269526361
Measure sort_by_lambda on 10000000 items:
Took 0.974274s to complete round
Took 0.97298s to complete round
Took 0.964506s to complete round
Took 0.96899s to complete round
Took 0.965773s to complete round
Took 0.96457s to complete round
Took 0.974286s to complete round
Took 0.975524s to complete round
Took 0.966238s to complete round
Took 0.964676s to complete round
Checksum: 18446656212269526361
Measure sort_by_functor on 10000000 items:
Took 0.964359s to complete round
Took 0.979619s to complete round
Took 0.974027s to complete round
Took 0.964671s to complete round
Took 0.964764s to complete round
Took 0.966491s to complete round
Took 0.964706s to complete round
Took 0.965115s to complete round
Took 0.964352s to complete round
Took 0.968954s to complete round
Checksum: 18446656212269526361
Measure sort_by_function on 10000000 items:
Took 1.29942s to complete round
Took 1.3029s to complete round
Took 1.29931s to complete round
Took 1.29946s to complete round
Took 1.29837s to complete round
Took 1.30132s to complete round
Took 1.3023s to complete round
Took 1.30997s to complete round
Took 1.30819s to complete round
Took 1.3003s to complete round
Checksum: 18446656212269526361
看起来除了传递函数指针以外的所有选项都非常相似,传递函数指针会导致+ 30%的损失。
看起来好像operator <版本慢了约1%(我多次重复测试并且效果仍然存在),这有点奇怪,因为它表明生成的代码是不同的(我缺乏分析--save-临时输出)。
是的,std::sort()
使用第三个参数(函数或对象)会更容易。例如:http :
//www.cplusplus.com/reference/algorithm/sort/
在您的课程中,您可以重载“ <”运算符。
class MyClass
{
bool operator <(const MyClass& rhs)
{
return this->key < rhs.key;
}
}
下面是使用lambdas的代码
#include "stdafx.h"
#include <vector>
#include <algorithm>
using namespace std;
struct MyStruct
{
int key;
std::string stringValue;
MyStruct(int k, const std::string& s) : key(k), stringValue(s) {}
};
int main()
{
std::vector < MyStruct > vec;
vec.push_back(MyStruct(4, "test"));
vec.push_back(MyStruct(3, "a"));
vec.push_back(MyStruct(2, "is"));
vec.push_back(MyStruct(1, "this"));
std::sort(vec.begin(), vec.end(),
[] (const MyStruct& struct1, const MyStruct& struct2)
{
return (struct1.key < struct2.key);
}
);
return 0;
}
// sort algorithm example
#include <iostream> // std::cout
#include <algorithm> // std::sort
#include <vector> // std::vector
using namespace std;
int main () {
char myints[] = {'F','C','E','G','A','H','B','D'};
vector<char> myvector (myints, myints+8); // 32 71 12 45 26 80 53 33
// using default comparison (operator <):
sort (myvector.begin(), myvector.end()); //(12 32 45 71)26 80 53 33
// print out content:
cout << "myvector contains:";
for (int i=0; i!=8; i++)
cout << ' ' <<myvector[i];
cout << '\n';
system("PAUSE");
return 0;
}
您可以使用用户定义的比较器类。
class comparator
{
int x;
bool operator()( const comparator &m, const comparator &n )
{
return m.x<n.x;
}
}
要对向量排序,可以使用中的sort()算法。
sort(vec.begin(),vec.end(),less<int>());
使用的第三个参数可以更大或更小,或者也可以使用任何功能或对象。但是,如果您将第三个参数留空,则默认运算符为<。
// using function as comp
std::sort (myvector.begin()+4, myvector.end(), myfunction);
bool myfunction (int i,int j) { return (i<j); }
// using object as comp
std::sort (myvector.begin(), myvector.end(), myobject);
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为假,它将执行“交换”。