8

class Person我希望根据其数据成员' '对对象数组进行排序age。我将对象存储在vector<Person> v.

据我了解,至少有 4 种方法可以执行此操作,并且根据下面编写的方法,我有以下问题。

  1. 在类中定义如何operator()工作?我不应该在这里重载“<”运算符吗?为什么 '()' ?

  2. 我在方法 1 中发送了一个对象作为第三个参数。但是,在方法 2 中,我发送了一个函数的名称。为什么会这样?

  3. 这四种方法哪一种最好?我觉得方法3是最简单的。

方法一

class cmp
{
public:
    bool operator() (  Person const &a,  Person const &b )
    {
        return a.age < b.age ;
    }
};

sort( v.begin(), v.end(), cmp());

方法二

bool cmp( const Person a, const Person b ) 
{
    return a.age < b.age ;
}

sort( v.begin(), v.end(), cmp );

方法三

bool operator < ( const Person a, const Person b )
{
    return a.age < b.age ;
}

sort( v.begin(), v.end());

方法四

//using lambda expression
sort( v.begin(), v.end(), [](const Person &a, const Person &b){return a.age < b.age;});
4

4 回答 4

9

要使用std::sort(或与此相关的任何函数)对范围进行排序,它需要知道如何比较范围中的两个元素,以确定小于(或大于)关系。

标准库函数std::sort两种风格:一种使用operator<,另一种使用比较函数/仿函数。您在代码中都使用了它们——特别是,示例中的第三个<使用了比较函数/函子。

至于哪一个是最好的方法?

这要看情况。使用的那个operator<不太灵活,因为它是固定的,但也需要更少的打字。足够时使用它。

另一个更灵活,因为您可以传递任何比较函数并相应地对元素进行排序。operator<不够用的时候用。此外,当您选择这种风格时,您还有其他选择:比较器可以是函数函子lambda — 如果您使用函数或函子(在命名空间级别定义),那么您可以重用它们;另一方面,lambda通常定义在函数范围内,因此它不是那么可重用,除非您在命名空间范围内定义它,在这种情况下它几乎与函数相同。

例如,假设您想按升序对 的向量进行排序int

 std::vector<int>  v{10, 3, 12, -26};
 std::sort(v.begin(), v.end());
 print(v);

输出:-26,3,10,12operator<做这项工作也是如此。

但是,如果您希望仅考虑大小(即忽略符号)对元素进行排序,那么您必须使用另一种风格:

 std::vector<int>  v{10, 3, 12, -26};
 auto abs_cmp = [](int a, int b) { return std::abs(a) < std::abs(b); };
 std::sort(v.begin(), v.end(), abs_cmp);
 print(v);

输出:3,10,12,-26。这是您在这种情况下所期望的输出。

希望有帮助。

于 2013-11-10T09:12:35.320 回答
4

sort 函数有两个重载

一世。 void sort( RandomIt first, RandomIt last );它不接受比较功能,它希望项目已operator<定义。您的方法 3 使用此重载。

template< class RandomIt >
void sort( RandomIt first, RandomIt last )
{
    ...

    if (*i < *j)
      ....

    ...
}

 

ii. void sort( RandomIt first, RandomIt last, Compare comp );它接受比较功能,当您的项目没有operator<定义时它很有用。

template< class RandomIt, class Compare >
void sort( RandomIt first, RandomIt last, Compare comp )
{
    ...

    if (comp(*i, *j))
      ....

    ...
}

方法 1、2、4 使用此重载。所有传递的第三个参数都可以由(). 方法一,通过 发送一个对象cmp(),这个对象已经重载operator(),上面的代码调用了它。方法 2 和 4,发送指向函数的指针,指向函数的指针可以被调用()

于 2013-11-10T09:12:04.010 回答
2

在类中定义的 operator() 是如何工作的?我不应该在这里重载“<”运算符吗?为什么 '()' ?

operator()是函数调用运算符。你的类的实例是cmp可以调用的,就像函数是可调用的一样。需要调用sort来执行必要的比较。

我在方法 1 中发送了一个对象作为第三个参数。但是,在方法 2 中,我发送了一个函数的名称。为什么会这样?

的实例cmp是可调用的。函数名称是可调用的。

这四种方法哪一种最好?我觉得方法3是最简单的。

3 的主要缺点是您根据年龄定义了一个人小于或大于另一个人。如果您想在其他地方按名称对它们进行排序怎么办?你已经operator<为 Person 定义了,所以你不能再做同样的把戏了。所有其他三种方法都定义了在特定排序中使用的比较,而不是定义 compare 的一般含义Person

2 的主要缺点是编译器比 1 或 4 更难内联。它与 1 相比并没有真正的优势,但为了完整性,它sort可以采用函数指针。

4 的主要优点是,如果您只使用一次比较,那么将它放在调用 的同一行代码中通常会更好sort,而不是在文件中的其他地方关闭。

1 的主要优点是它可以在 C++03 中工作(与 4 不同)。4 或多或少是 1 的新语法。1 还具有使比较器可用于其他代码以使用相同名称的优点。如果需要,您也可以使用 lambda 来实现这一点(通过将 lambda 分配给auto变量来命名它)。

于 2013-11-10T09:28:05.393 回答
1
  1. 您只需提供具有 operator() 并在比较对象时使用的functor对象。
  2. 据我所知,sort 接受函子、函数和 lambda 表达式来使用它们来比较对象。
  3. 在方法 3 中,您不提供要比较的函子、函数或 lambda 表达式,因此默认情况下使用标准 operator< 对其进行排序。显然,它不会像您希望的那样按年龄对您的 Person 对象进行排序。在我看来,最简洁的形式是方法 4,使用 lambda 表达式。
于 2013-11-10T09:13:14.153 回答