繁体   English   中英

与三值比较函数相比,仅使用小于运算符进行排序

[英]Sorting only using the less-than operator compared to a trivalue compare function

在C ++ / STL中,仅使用less-than运算符进行排序。 尽管我不知道排序算法是如何实际实现的,但我认为其他操作是隐含的:

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

与使用trivalue * compare函数(例如Java)相比,这对性能有好处,或者为什么要做出这样的设计决策呢?

我的假设是,任何trivalue compareto函数仍然必须实现这些比较,从而产生相同的性能。

**通过trivalue比较函数,我的意思是比较函数,它返回-1,0和1小于,等于和大于*

更新:似乎太空船<=>运营商正在使用C ++ 20,所以显然委员会认为仅使用operator<缺点。

从某种意义上说,另外两个是隐式的,但更准确的是说比较排序实际上并不需要三值比较器,并且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 ++指的是“严格的弱排序”。 如果<是严格的弱排序,并且!(a < b) && !(b < a) ,则不一定遵循a == b 它们在排序中只是“在同一个地方”,并且!(a < b) && !(b < a)是等价关系。 因此,所要求的比较sort顺序等价 ,它并没有提供一个总订单。

唯一的区别就是你说的时候!(a < b) 对于严格的总订单,您将推导出b <= a ,读取“小于或等于”。 对于严格的弱序,您不能将b <= a定义为b < a || b == a b < a || b == a并且这是真的。 C ++对此很迂腐,因为它允许运算符重载它几乎必须如此,因为人们重载运算符需要术语,以便告诉用户他们的代码在运算符如何关联方面可以期待什么。 Java确实讨论了比较器和hashCode与equals一致,这就是你所需要的。 C ++必须处理<,>,==,<=,> =,赋值的后置条件,等等。

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

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

我在C ++中的猜测只是为了减少代码重复:一旦你在类/类型上定义了一个比较操作,你不仅可以通过简单地写一个<b来比较这些对象,而且还可以对这些对象进行排序。这样的对象。

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

如果你指的是std :: sort(),它只使用less()运算符,因为它不需要保留等效元素的相对排序,所以它只需要less()运算符和隐式big()运算符。

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

暂无
暂无

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

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