C++ 是否支持C++/用于按属性对对象进行排序的STL?
我想知道STL中是否支持这一点: 假设我有这样一门课:C++ 是否支持C++/用于按属性对对象进行排序的STL?,c++,sorting,stl,attributes,C++,Sorting,Stl,Attributes,我想知道STL中是否支持这一点: 假设我有这样一门课: class Person { public: int getAge() const; double getIncome() const; .. .. }; 和一个向量: vector<Person*> people; 矢量人; 我想按年龄对人群进行分类: 我知道我可以通过以下方式完成: class AgeCmp { public: bool operator() ( const Person* p1,
class Person
{
public:
int getAge() const;
double getIncome() const;
..
..
};
和一个向量:
vector<Person*> people;
矢量人;
我想按年龄对人群进行分类:
我知道我可以通过以下方式完成:
class AgeCmp
{
public:
bool operator() ( const Person* p1, const Person* p2 ) const
{
return p1->getAge() < p2->getAge();
}
};
sort( people.begin(), people.end(), AgeCmp() );
class-AgeCmp
{
公众:
布尔运算符()(常数人*p1,常数人*p2)常数
{
返回p1->getAge()getAge();
}
};
排序(people.begin()、people.end()、AgeCmp());
有没有一种不那么冗长的方法?仅仅因为我想基于“属性”进行排序,就必须定义一个完整的类,这似乎有些过分。也许是这样的
sort( people.begin(), people.end(), cmpfn<Person,Person::getAge>() );
sort(people.begin()、people.end()、cmpfn());
如果您只想根据一件事对人员进行排序(或者如果您想在大多数时间使用合理的默认值),则覆盖运算符您可以只使用全局函数或静态函数。这些全局或静态函数中的每一个都与一个属性进行比较。不需要上课。保存参数进行比较的一种方法是使用boost-bind,但bind仅用于查找所有类或将所有类与某个绑定参数进行比较。跨多个元素存储数据是生成函子的唯一原因
编辑:另请参见boost lambda函数,但它们仅适用于简单函数。您不需要创建类,只需编写函数即可:
#include <vector>
#include <algorithm>
using namespace std;
struct Person {
int age;
int getage() const {
return age;
}
};
bool cmp( const Person * a, const Person * b ) {
return a->getage() < b->getage() ;
}
int main() {
vector <Person*> v;
sort( v.begin(), v.end(), cmp );
}
#include <functional>
template <class Object, class ResultType>
class CompareAttributeT: public std::binary_function<const Object*, const Object*, bool>
{
typedef ResultType (Object::*Getter)() const;
Getter getter;
public:
CompareAttributeT(Getter method): getter(method) {}
bool operator()(const Object* lhv, const Object* rhv) const
{
return (lhv->*getter)() < (rhv->*getter)();
}
};
template <class Object, class ResultType>
CompareAttributeT<Object, ResultType> CompareAttribute(ResultType (Object::*getter)() const)
{
return CompareAttributeT<Object, ResultType>(getter);
}
#包括
#包括
使用名称空间std;
结构人{
智力年龄;
int getage()常量{
回归年龄;
}
};
布尔cmp(常数人*a,常数人*b){
返回a->getage()getage();
}
int main(){
向量v;
排序(v.begin(),v.end(),cmp);
}
基于成员属性进行比较的通用适配器。虽然它在第一次可重用时更加冗长
// Generic member less than
template <typename T, typename M, typename C>
struct member_lt_type
{
typedef M T::* member_ptr;
member_lt_type( member_ptr p, C c ) : ptr(p), cmp(c) {}
bool operator()( T const & lhs, T const & rhs ) const
{
return cmp( lhs.*ptr, rhs.*ptr );
}
member_ptr ptr;
C cmp;
};
// dereference adaptor
template <typename T, typename C>
struct dereferrer
{
dereferrer( C cmp ) : cmp(cmp) {}
bool operator()( T * lhs, T * rhs ) const {
return cmp( *lhs, *rhs );
}
C cmp;
};
// syntactic sugar
template <typename T, typename M>
member_lt_type<T,M, std::less<M> > member_lt( M T::*ptr ) {
return member_lt_type<T,M, std::less<M> >(ptr, std::less<M>() );
}
template <typename T, typename M, typename C>
member_lt_type<T,M,C> member_lt( M T::*ptr, C cmp ) {
return member_lt_type<T,M,C>( ptr, cmp );
}
template <typename T, typename C>
dereferrer<T,C> deref( C cmp ) {
return dereferrer<T,C>( cmp );
}
// usage:
struct test { int x; }
int main() {
std::vector<test> v;
std::sort( v.begin(), v.end(), member_lt( &test::x ) );
std::sort( v.begin(), v.end(), member_lt( &test::x, std::greater<int>() ) );
std::vector<test*> vp;
std::sort( v.begin(), v.end(), deref<test>( member_lt( &test::x ) ) );
}
//泛型成员小于
模板
结构成员类型
{
类型定义M T::*成员;
成员类型(成员类型p,cc):ptr(p),cmp(C){}
布尔运算符()
{
返回cmp(左侧。*ptr,右侧。*ptr);
}
成员(ptr ptr),;
C化学机械抛光;
};
//解引用适配器
模板
结构解除器
{
德里费雷尔(cmp):cmp(cmp){
布尔运算符()(T*lhs,T*rhs)常量{
返回cmp(*左侧,*右侧);
}
C化学机械抛光;
};
//句法糖
模板
成员类型成员(M T::*ptr){
返回成员类型(ptr,std::less());
}
模板
成员类型成员(M T::*ptr,C cmp){
返回成员类型(ptr、cmp);
}
模板
dereferrer deref(C cmp){
返回去铁器(cmp);
}
//用法:
结构测试{int x;}
int main(){
std::向量v;
std::sort(v.begin()、v.end()、member_lt(&test::x));
std::sort(v.begin(),v.end(),member_lt(&test::x,std::greater());
std::向量vp;
std::sort(v.begin()、v.end()、deref(member_lt(&test::x));
}
我看到dribeas已经发布了这个想法,但既然我已经编写了它,下面是如何编写一个通用的比较器来使用getter函数
#include <functional>
template <class Object, class ResultType>
class CompareAttributeT: public std::binary_function<const Object*, const Object*, bool>
{
typedef ResultType (Object::*Getter)() const;
Getter getter;
public:
CompareAttributeT(Getter method): getter(method) {}
bool operator()(const Object* lhv, const Object* rhv) const
{
return (lhv->*getter)() < (rhv->*getter)();
}
};
template <class Object, class ResultType>
CompareAttributeT<Object, ResultType> CompareAttribute(ResultType (Object::*getter)() const)
{
return CompareAttributeT<Object, ResultType>(getter);
}
我认为对非指针重载运算符()
可能是个好主意,但这样一来,就无法通过继承二进制函数来定义参数类型了,这可能不是一个很大的损失,因为在需要这些参数的地方使用它会很困难,例如,无论如何,我们都无法否定比较函子。这与其说是一个答案本身,不如说是对阿拉克对我的评论的回答,即用函数而不是函子排序会更慢。下面是一些比较各种排序的测试代码(当然很难看——CnP太多了):qsort、std::sort of vector vs.array和std::sort使用模板类、模板函数或普通函数进行比较:
#include <vector>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
int compare(void const *a, void const *b) {
if (*(int *)a > *(int *)b)
return -1;
if (*(int *)a == *(int *)b)
return 0;
return 1;
}
const int size = 200000;
typedef unsigned long ul;
void report(char const *title, clock_t ticks) {
printf("%s took %f seconds\n", title, ticks/(double)CLOCKS_PER_SEC);
}
void wait() {
while (clock() == clock())
;
}
template <class T>
struct cmp1 {
bool operator()(T const &a, T const &b) {
return a < b;
}
};
template <class T>
bool cmp2(T const &a, T const &b) {
return a<b;
}
bool cmp3(int a, int b) {
return a<b;
}
int main(void) {
static int array1[size];
static int array2[size];
srand(time(NULL));
for (int i=0; i<size; i++)
array1[i] = rand();
const int iterations = 100;
clock_t total = 0;
for (int i=0; i<iterations; i++) {
memcpy(array2, array1, sizeof(array1));
wait();
clock_t start = clock();
qsort(array2, size, sizeof(array2[0]), compare);
total += clock()-start;
}
report("qsort", total);
total = 0;
for (int i=0; i<iterations; i++) {
memcpy(array2, array1, sizeof(array1));
wait();
clock_t start = clock();
std::sort(array2, array2+size);
total += clock()- start;
}
report("std::sort (array)", total);
total = 0;
for (int i=0; i<iterations; i++) {
memcpy(array2, array1, sizeof(array1));
wait();
clock_t start = clock();
std::sort(array2, array2+size, cmp1<int>());
total += clock()- start;
}
report("std::sort (template class comparator)", total);
total = 0;
for (int i=0; i<iterations; i++) {
memcpy(array2, array1, sizeof(array1));
wait();
clock_t start = clock();
std::sort(array2, array2+size, cmp2<int>);
total += clock()- start;
}
report("std::sort (template func comparator)", total);
total = 0;
for (int i=0; i<iterations; i++) {
memcpy(array2, array1, sizeof(array1));
wait();
clock_t start = clock();
std::sort(array2, array2+size, cmp3);
total += clock()- start;
}
report("std::sort (func comparator)", total);
total = 0;
for (int i=0; i<iterations; i++) {
std::vector<int> array3(array1, array1+size);
wait();
clock_t start = clock();
std::sort(array3.begin(), array3.end());
total += clock()-start;
}
report("std::sort (vector)", total);
return 0;
}
我相信这些可以很清楚地分为三类:使用带有默认比较的sort和使用template类生成最快的代码。使用函数或模板函数显然较慢。使用qsort是(令人惊讶的是)最慢的,大约是2:1
cmp2和cmp3之间的差异似乎完全源于通过引用传递与通过值传递——如果您将cmp2更改为通过值获取其参数,则其速度与cmp3完全匹配(至少在我的测试中是这样)。不同之处在于,如果您知道类型将是int
,您几乎肯定会按值传递,而对于泛型T
,您通常会按常量引用传递(以防万一它的复制成本更高)。我只是根据Uncleben和david rodriguez Dribea的想法尝试了这个方法
这似乎在我当前的编译器中起作用。g++3.2.3。请让我知道它是否适用于其他编译器
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
class Person
{
public:
Person( int _age )
:age(_age)
{
}
int getAge() const { return age; }
private:
int age;
};
template <typename T, typename ResType>
class get_lt_type
{
ResType (T::*getter) () const;
public:
get_lt_type(ResType (T::*method) () const ):getter(method) {}
bool operator() ( const T* pT1, const T* pT2 ) const
{
return (pT1->*getter)() < (pT2->*getter)();
}
};
template <typename T, typename ResType>
get_lt_type<T,ResType> get_lt( ResType (T::*getter) () const ) {
return get_lt_type<T, ResType>( getter );
}
int main() {
vector<Person*> people;
people.push_back( new Person( 54 ) );
people.push_back( new Person( 4 ) );
people.push_back( new Person( 14 ) );
sort( people.begin(), people.end(), get_lt( &Person::getAge) );
for ( size_t i = 0; i < people.size(); ++i )
{
cout << people[i]->getAge() << endl;
}
// yes leaking Persons
return 0;
}
#包括
#包括
#包括
使用名称空间std;
班主任
{
公众:
个人(国际年龄)
:年龄
{
}
int getAge()常量{return age;}
私人:
智力年龄;
};
模板
类获取\u lt\u类型
{
重新键入(T::*getter)()常量;
公众:
get_lt_type(ResType(T::*method)()const):getter(method){
布尔运算符()(常数T*pT1,常数T*pT2)常数
{
返回(pT1->*getter)(<(pT2->*getter)();
}
};
模板
get_lt_type get_lt(ResType(T::*getter))常量){
返回get\u lt\u类型(getter);
}
int main(){
媒介人;
人。推回(新的人(54));
人。推回(新的人(4));
人。推回(新的人(14));
排序(people.begin()、people.end()、get\lt(&Person::getAge));
对于(size_t i=0;i cout getAge()这些答案都非常详细,尽管我喜欢模板的想法!只需使用lambda函数,它会让事情变得简单得多
你可以用这个:
sort( people.begin(), people.end(), []( Person a, Person b ){ return a.age < b.age; } );
排序(people.begin(),people.end(),[](persona,personb){返回a.age
对向量进行排序
sort( people.begin(), people.end(), []( Person a, Person b ){ return a.age < b.age; } );