【问题标题】:Sorting only using the less-than operator compared to a trivalue compare function与三值比较函数相比,仅使用小于运算符进行排序
【发布时间】:2011-01-24 01:10:27
【问题描述】:

在 C++/STL 中,排序仅使用小于运算符完成。虽然我不知道排序算法是如何实际实现的,但我假设其他操作是隐式创建的:

a > b *equals* b < a == true
a == b *equals* !(a < b) && !(b < a)

与使用三值*比较函数(例如 Java)相比,这对性能有好处吗?或者为什么做出这个设计决定?

我的假设是任何三值 compareto 函数仍然必须自己实现这些比较,从而获得相同的性能。

**通过三值比较函数,我的意思是一个比较函数,它返回-1、0和1代表小于、等于和大于*

更新: 似乎宇宙飞船 &lt;=&gt; 运算符将出现在 C++20 中,因此显然委员会认为仅使用 operator&lt; 存在缺点。

【问题讨论】:

标签: c++ sorting stl operator-overloading spaceship-operator


【解决方案1】:

在某种意义上,其他两个是隐含的,但更准确的说法是比较排序实际上并不需要一个三值比较器,而 C++ 的排序是以一种方式实现的不使用一个来最小化比较器所需的行为。

std::sort 定义和专门使用这样的东西是错误的:

template <typename T, typename Cmp>
int get_tri_value(const T &a, const T &b, Cmp lessthan) {
    if (lessthan(a,b)) return -1;
    if (lessthan(b,a)) return 1;
    return 0;
}

...因为在调用lessthan 的次数方面,您最终会得到一个低效的算法。如果您的算法对返回 1 和返回 0 之间的差异没有任何用处,那么您就浪费了比较。

C++ 指的是“严格的弱排序”。如果&lt; 是严格的弱排序,而!(a &lt; b) &amp;&amp; !(b &lt; a),则它必然遵循a == b。它们在排序中只是“在同一个地方”,!(a &lt; b) &amp;&amp; !(b &lt; a) 是等价关系。所以sort 需要的比较器对对象的等价类进行排序,它不提供总排序。

唯一不同的是你在!(a &lt; b) 时所说的话。对于严格的总顺序,您可以推断出b &lt;= a,阅读“小于或等于”。对于严格的弱顺序,您不能将 b &lt;= a 定义为表示 b &lt; a || b == a 并让它成为真的。 C++ 对此很迂腐,因为它允许运算符重载,所以它几乎必须如此,因为重载运算符的人需要行话来告诉用户他们的代码他们在运算符之间的关系方面可以期待什么。 Java确实谈到了比较器和hashCode与equals一致,这就是你所需要的。 C++要处理、==、=、赋值的后置条件等等。

C++ 在 API 中对此采用了相当纯粹的数学方法,因此所有内容都根据单个二进制关系进行定义。 Java 在某些方面更友好,并且更喜欢三路比较,其中基本单元的定义(比较)有点复杂,但由此得出的逻辑更简单。这也意味着排序算法每次比较都会获得更多信息,这有时很有用。例如,请参阅“荷兰国旗”快速排序优化,当数据中有大量“在同一个地方”重复时,这是一个好处。

在这种情况下,三值比较器是速度增益。但是 C++ 使用一致的比较器定义进行排序,也用于setmaplower_bound 等,它们几乎没有从三值比较器中受益(可能保存一个比较,可能没有)。我猜他们为了特定或有限的潜在效率提升而决定不使他们漂亮的通用界面复杂化。

【讨论】:

    【解决方案2】:

    我在 C++ 中的猜测只是为了减少代码重复:一旦你在一个类/类型上定义了一个比较操作,你不仅能够通过简单地编写 a

    至于排序,我们只需要小于运算符,为什么要引入额外的东西? :)

    【讨论】:

      【解决方案3】:

      如果你指的是 std::sort(),它只使用 less() 运算符,因为它不需要保留等效元素的相对顺序,所以它只需要 less() 运算符,并且隐式地更大( ) 操作员。

      虽然 std::stable_sort 会保留它,但速度较慢。它需要 less() 运算符和双向迭代器来交换 equal() 运算符来构造“三值”比较函数

      【讨论】:

      • 不确定我是否遵循您关于需要双向迭代器的观点。两者都需要随机访问迭代器(例如不会对列表进行排序)。
      猜你喜欢
      • 2016-03-31
      • 1970-01-01
      • 2018-05-29
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 2012-09-26
      • 2014-05-10
      • 2020-12-05
      相关资源
      最近更新 更多