【问题标题】:Would C++ standard algorithms be faster if comparators were required to be strict total orderings rather than just strict weak orderings?如果要求比较器是严格的总排序而不是严格的弱排序,C++ 标准算法会更快吗?
【发布时间】:2020-04-17 18:07:29
【问题描述】:

许多 C++ 标准算法,例如 std::sort(),假定 the comparator compstrict weak ordering,并且不能假定 comp 具有任何其他(好的)属性。但很多时候comp 确实有更多的属性,而不仅仅是严格的弱排序。特别是,很多时候compstrict total order(所以特别是,对于所有abcomp(a, b)comp(b, a)a = b,以下其中一个总是正确的)。例如,浮点数、整数和std::strings 上的常用operator<() 都是严格的全序。

通过将自身限制为假设comp 是严格的弱排序,C++ 标准库是否将自身限制为使用次优算法?换句话说,如果 C++ 标准算法假设比较器是严格的总排序而不是严格的弱排序,那么某些标准算法会比目前实现的更快吗?

更新:为了更准确地了解“严格的总排序”的含义,我们假设 STL 假设 comp(对 T 类型的对象进行操作)具有 @987654341 所具有的所有良好的排序理论属性@ on ints 有。 (因此,如果您愿意,我们还可以假设在 T 类型的对象上定义了一个 operator==(),它可以按您的预期工作;这个假设是可选的,如果您愿意,您可以做出不同的假设。 ) 可以使任何 STL 算法更快吗?

更一般地说,如果 STL 对 comp 做出“更好”的假设(即假设更多 comp 只是严格的弱排序),那么任何 STL 算法都可以做得更快吗?

【问题讨论】:

  • @curiousguy cc Matt,在 C++20 之前,您必须自己制作。在 C++20 中,您可以检查返回类型是否为 std::strong_ordering,这是严格总订单比较的新返回类型。见en.cppreference.com/w/cpp/language/default_comparisons
  • 请注意,由于NaN,浮点数上的operator< 不是严格的排序。
  • @n314159 你不必使用这些非值。
  • 不知道有没有用,因为我不是很懂,但是Java要求Comparators有总排序,如果不这样做,@ 987654325@。这意味着浮点类型的排序方法对 NaN 进行了特殊处理,将其与普通比较运算符进行了不同的比较。我不确定为什么 Java 需要总排序。
  • @JaMiT 我开发了一种算法,如果比较器是一个总订单,则可以更有效地实现该算法。所以我想知道是否有任何 STL 算法存在类似的情况。

标签: c++ algorithm std comparator


【解决方案1】:

例如,通常的operator<() 对浮点数、整数和 std::strings都是严格的总订单。

所以你只是在谈论状态的相似性,而不是真正的平等(无论在具有可变状态的语言中是什么)。

通过将自身限制为仅假设 comp 是严格的弱 排序,C++ 标准库本身是否有限制

没有。前提是错误的。根据定义,容器和算法库(生成排序序列的算法、在排序范围上操作的算法以及有序关联容器) 不会以任何方式限制自身:它明确表示等价关系,据我所知,它没有被命名(我们称之为Sim)可以根据比较来定义:

Sim (x,y) !Comp(x,y) && !Comp(y,x)

所以你有你的严格命令,只需将 Sim 称为“平等”并重载 operator== 以定义为 Sim

所以唯一的问题是使用二进制比较函数很愚蠢,这意味着对 f.ex 进行多次扫描。确定相等性的字符串,并且无法访问三元比较(如strcmp)。如果您可以直接访问 Sim,那么在相等的情况下,您仍然会调用 Comp 而不是 Sim,或者调用 Comp > 然后是另一个Comp

只有当你先验怀疑“平等”是最可能的结果时,你才会使用Sim然后Comp。这太荒谬了。

三种方式更适合比较序列。走三路。

【讨论】:

  • 另见Compare requirement OP 正在链接:“注意:comp 对由 equiv 确定的等价类产生严格的总排序。”因此,算法使用严格的总排序,因为它查看所有等效值,就好像它们相等。
  • @n314159 "查看所有等效值,就好像它们相等" 哪个是这样做的?
  • A lot of them 链接页面上列出的几乎所有关于比较要求的内容。
  • @n314159 我的意思是,如果你插入d1 然后d2,第二个不会替换第一个。
  • 当有人使用像std::set这样的容器时,他应该知道(1)他想比较哪些成员,如果(2)是否应该忽略第二个插入(在这种情况下,std::mapstd::multiset 可能是更好的选择,具体取决于具体需要)。
猜你喜欢
  • 1970-01-01
  • 2010-11-02
  • 2013-02-14
  • 2020-02-18
  • 2010-11-20
  • 2015-09-20
  • 2016-02-04
  • 2018-04-17
  • 1970-01-01
相关资源
最近更新 更多