如何对包含自定义(即用户定义的)对象的向量进行排序。 可能,应该使用标准的STL算法排序以及一个谓词(函数或函数对象),该谓词将对自定义对象中的一个字段(作为排序的键)进行操作。 我的思路对吗?


当前回答

您可以使用functor作为std::sort的第三个参数,或者您可以在类中定义操作符<。

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() );
}

其他回答

在类中,可以重载"<"操作符。

class MyClass
{
  bool operator <(const MyClass& rhs)
  {
    return this->key < rhs.key;
  }
}

您可以使用用户定义的比较器类。

class comparator
{
    int x;
    bool operator()( const comparator &m,  const comparator &n )
    { 
       return m.x<n.x;
    }
 }

下面是使用lambdas的代码

#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;
}

一个使用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());

编辑:正如Kirill V. Lyadvinsky指出的那样,你可以为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>());

对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));