简体   繁体   English

C ++ STL - STL sort()的第三个参数如何工作?

[英]C++ STL - How does the third argument of the STL sort() work?

I wish to sort an array of objects of class Person on the basis of its data member ' age '. 我希望根据其数据成员' age '对class Person的对象数组进行排序。 I store the objects in a vector<Person> v . 我将对象存储在vector<Person> v

As far I have understood, there can be at least 4 ways to perform this action and I have the following questions based on the methods written below. 据我所知,至少有4种方法可以执行此操作,我根据下面的方法提出以下问题。

  1. How does operator() defined inside a class work? 如何在类中定义operator()工作? Should I not overload the '<' operator here as well? 我不应该在这里重载“<”运算符吗? Why '()' ? 为什么'()'?

  2. I sent an object as the 3rd parameter in method 1. But, in method 2, I sent the name of a function. 我在方法1中发送了一个对象作为第3个参数。但是,在方法2中,我发送了一个函数的名称。 Why is it like that? 为什么会那样?

  3. Which of the four methods is the best? 四种方法中哪一种最好? I felt that method 3 was the easiest. 我觉得方法3是最简单的。

Method 1 方法1

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

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

Method 2 方法2

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

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

Method 3 方法3

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

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

Method 4 方法4

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

To sort a range using std::sort (or any function for that matter), it needs to know how two elements from the range are compared , in order to determine less than (or greater than) relationship. 要使用std::sort (或任何函数)对范围进行std::sort ,它需要知道如何比较范围中的两个元素,以确定小于(或大于)的关系。

The Standard Library function std::sort comes in two flavors: one uses operator< , the other uses a compare function/functor. 标准库函数std::sort两种形式 :一种使用operator< ,另一种使用compare函数/ functor。 You've used both of them in your code — in particular, the third one in your example uses < and the rest use compare function/functor. 您已经在代码中使用了它们 - 特别是,示例中的第三个使用< ,其余使用比较函数/仿函数。

As for which one is the best approach? 至于哪一个是最好的方法?

Well, it depends. 这要看情况。 The one which uses operator< is less flexible since it is fixed but requires you less typing as well. 使用operator<那个不太灵活,因为它是固定的,但也需要你少输入。 Use it when it suffices. 当它足够时使用它。

The other one is more flexible as you can pass any compare function and get your elements sorted accordingly. 另一个更灵活,因为您可以传递任何比较功能并相应地对您的元素进行排序。 Use it when operator< doesn't suffice. operator<不够时使用它。 Also, when you choose this flavor, you have other choices as well : the comparer could be a function , a functor , or a lambda — if you use function or functor (defined at namespace level), then you can reuse them; 此外,当你选择这种风格时,你还有其他选择:比较器可以是函数函子lambda - 如果你使用函数或函子(在命名空间级别定义),那么你可以重用它们; on the other hand, lambda is usually defined in a function scope, so it is not that reusable, unless you define it at namespace scope, in which case it is almost same as function. 另一方面,lambda 通常在函数范围内定义,因此它不是可重用的,除非你在命名空间范围内定义它,在这种情况下它几乎与函数相同。

Example, suppose you want to sort a vector of int in increasing order: 例如,假设您要按递增顺序对int的向量进行排序:

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

Output: -26,3,10,12 . 产量: -26,3,10,12 So operator< does do the job. 所以operator<确实做到了。

But what if you want the elements sorted considering only magnitude (ie ignore signs), then you have to use the other flavor: 但是如果你想要仅考虑幅度 (即忽略符号)排序的元素,那么你必须使用另一种风格:

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

Output : 3,10,12,-26 . 输出: 3,10,12,-26 That is the output you would expect in this case. 这是您在这种情况下期望的输出。

Hope that helps. 希望有所帮助。

The sort function has two overloads sort函数有两个重载

i. 一世。 void sort( RandomIt first, RandomIt last ); It doesn't accept compare function, it expects the items have operator< defined. 它不接受比较函数,它期望项目具有operator<定义的operator< You'r method 3 uses this overload. 你的方法3使用这个重载。

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

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

    ...
}

ii. II。 void sort( RandomIt first, RandomIt last, Compare comp ); it accepts a compare function, it's useful when your items don't have operator< defined. 它接受比较功能,当你的物品没有operator<定义的operator<时,它很有用。

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

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

    ...
}

Methods 1,2,4 use this overload. 方法1,2,4使用此重载。 All the passed third arguments can be called by () . 所有传递的第三个参数都可以通过()调用。 Method 1, sends an object by cmp() , this object has overloaded operator() and above code invokes it. 方法1,通过cmp()发送一个对象,这个对象有重载的operator()和上面的代码调用它。 Method 2 and 4, sends pointer to functions and a pointer to a function can be invoked by () . 方法2和4,发送指向函数的指针,指向函数的指针可以由()调用。

How does operator() defined inside a class work? 如何在类中定义operator()工作? Should I not overload the '<' operator here as well? 我不应该在这里重载“<”运算符吗? Why '()' ? 为什么'()'?

operator() is the function call operator. operator()是函数调用运算符。 Instances of your class cmp are callable in the same way that a function is callable. cmp实例可以与函数可调用的方式相同的方式调用。 The call is required by sort to perform the necessary comparison. sort需要调用以执行必要的比较。

I sent an object as the 3rd parameter in method 1. But, in method 2, I sent the name of a function. 我在方法1中发送了一个对象作为第3个参数。但是,在方法2中,我发送了一个函数的名称。 Why is it like that? 为什么会那样?

Instances of cmp are callable. cmp实例是可调用的。 Function names are callable. 函数名称是可调用的。

Which of the four methods is the best? 四种方法中哪一种最好? I felt that method 3 was the easiest. 我觉得方法3是最简单的。

The main disadvantage of 3 is that you have defined that one Person is less than or greater than another Person according to their ages. 3的主要缺点是你已经根据他们的年龄定义了一个人小于或大于另一个人。 What if you want to sort them by name elsewhere? 如果你想在其他地方按名称排序怎么办? You've already defined operator< for Person, so you can't do the same trick again. 您已经定义了operator< for Person,因此您无法再次执行相同的操作。 All three of the other methods define a comparison for use in a specific sort, rather than defining what it means in general to compare Person . 所有其他三种方法都定义了在特定排序中使用的比较,而不是定义比较Person一般含义。

The main disadvantage of 2 is that it's somewhat harder for the compiler to inline than 1 or 4. It doesn't really have any advantages over 1, but for completeness it's nice that sort can take a function pointer. 2的主要缺点是编译器内联比1或4更难。它没有超过1的任何优点,但为了完整性, sort可以采用函数指针。

The main advantage of 4 is that if you only use the comparison once, it's often nicer to have it right there in the same line of code that calls sort , instead of being off somewhere else in the file. 4的主要优点是,如果你只使用一次比较,那么在调用sort的同一行代码中将它放在那里通常更好,而不是在文件的其他地方。

The main advantage of 1 is that it works in C++03 (unlike 4). 1的主要优点是它适用于C ++ 03(与4不同)。 4 is more-or-less a new syntax for 1. 1 also has the advantage that it makes the comparator available for other code to use with the same name. 4或多或少是1的新语法.1还具有使比较器可用于其他代码以使用相同名称的优点。 You could achieve that with a lambda too if you wanted (you name a lambda by assigning it to an auto variable). 如果你想要的话,你也可以用lambda来实现(通过将lambda命名为auto变量来命名lambda)。

  1. You simply provide functor , object that has operator() and is used while comparing objects. 您只需提供functor ,具有operator()的对象,并在比较对象时使用。
  2. As far as I know, sort accepts functors, functions and lambda expressions to use them to compare objects. 据我所知,sort接受函子,函数和lambda表达式来使用它们来比较对象。
  3. In method 3 you doesn't provide functor, function or lambda expression to compare so it's by default sorted using standard operator<. 在方法3中,您不提供functor,function或lambda表达式进行比较,因此默认情况下使用标准运算符<。 Obviously it doesn't sort your Person objects by age, as you would like to. 显然,它不会按照您的意愿按年龄对Person对象进行排序。 In my opinion the cleanest form is method 4, using lambda expression. 在我看来,最干净的形式是方法4,使用lambda表达式。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM