【问题标题】:C++ STL - How does the third argument of the STL sort() work?C++ STL - STL sort() 的第三个参数如何工作?
【发布时间】:2013-11-10 09:04:36
【问题描述】:

我希望根据其数据成员“age”对class Person 的对象数组进行排序。我将对象存储在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 );

方法3

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

【问题讨论】:

    标签: c++ sorting stl lambda


    【解决方案1】:

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

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

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

    嗯,这取决于。使用operator&lt; 的那个不太灵活,因为它是固定的,但也需要更少的输入。足够时使用它。

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

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

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

    输出:-26,3,10,12。所以operator&lt; 确实可以完成这项工作。

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

     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。这就是您在这种情况下所期望的输出。

    希望对您有所帮助。

    【讨论】:

      【解决方案2】:

      排序函数有两个重载

      i. void sort( RandomIt first, RandomIt last ); 它不接受比较功能,它希望项目已定义operator&lt;。你的方法 3 使用了这个重载。

      template< class RandomIt >
      void sort( RandomIt first, RandomIt last )
      {
          ...
      
          if (*i < *j)
            ....
      
          ...
      }
      

       

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

      template< class RandomIt, class Compare >
      void sort( RandomIt first, RandomIt last, Compare comp )
      {
          ...
      
          if (comp(*i, *j))
            ....
      
          ...
      }
      

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

      【讨论】:

        【解决方案3】:

        在类中定义的 operator() 是如何工作的?我不应该在这里重载“

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

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

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

        四种方法中哪种方法最好?我觉得方法3最简单。

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

        2 的主要缺点是编译器比 1 或 4 更难内联。它实际上并没有比 1 有任何优势,但为了完整性,sort 可以采用函数指针是很好的。

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

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

        【讨论】:

          【解决方案4】:
          1. 您只需提供 functor,即具有 operator() 并在比较对象时使用的对象。
          2. 据我所知,sort 接受函子、函数和 lambda 表达式以使用它们来比较对象。
          3. 在方法 3 中,您不提供函子、函数或 lambda 表达式进行比较,因此默认情况下使用标准运算符

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-06-03
            • 1970-01-01
            • 1970-01-01
            • 2023-03-15
            • 2014-12-07
            • 2014-12-29
            • 1970-01-01
            相关资源
            最近更新 更多