【问题标题】:Operator< and strict weak ordering运算符<和严格的弱排序
【发布时间】:2010-11-02 01:26:19
【问题描述】:

如何在 n 元组(例如在 3 元组)上定义 operator&lt; 以满足 严格弱排序 概念?我知道 boost 库有正确定义 operator&lt; 的元组类,但由于某些原因我不能使用它。

【问题讨论】:

  • 请澄清:您是在谈论定义 operator

标签: c++ strict-weak-ordering


【解决方案1】:
if (a1 < b1)
  return true;
if (b1 < a1)
  return false;

// a1==b1: continue with element 2
if (a2 < b2)
  return true;
if (b2 < a2)
  return false;

// a2 == b2: continue with element 3
if (a3 < b3)
  return true;
return false; // early out

这按 a1 最重要和 a3 最不重要对元素进行排序。

这可以无限继续,你也可以例如将其应用于 T 的向量,迭代 a[i]

while (i<count-1 && !(a[i] < a[i+1]) && !(a[i+1] < a[i])
  ++i;
return i < count-1 && a[i] < a[i+1];

当然,如果比较开销很大,您可能希望缓存比较结果。


[edit] 删除错误代码


[编辑] 如果不止operator&lt; 可用,我倾向于使用该模式

if (a1 != b1)
  return a1 < b1;

if (a2 != b2)
  return a2 < b2;

...

【讨论】:

  • 这假设问题是关于元组内的排序,而不是我假设的,元组之间的排序。
  • 好的,编辑后的代码在元组之间比较和排序,而不是在内部。我想!
  • 是的,在效果中添加了注释,但没有通过。原始代码真的很棒。我可以声称它显示了原理而实际上没有做任何有用的事情,但是....
  • 虽然如果你有迭代器,就像你的向量示例一样,只需使用std::lexographical_compare
  • 这是Lexicographical ordering 的实现——n 元组上许多可能的严格弱排序之一。
【解决方案2】:

您可以简单地使用三元素向量,它已经适当地具有 operator

【讨论】:

    【解决方案3】:

    即使你不能使用 boost 版本,你也应该可以修改代码。我从 std::pair 中删除了这个 - 我猜 3 元组会很相似。

    return (_Left.first < _Right.first ||
            !(_Right.first < _Left.first) && _Left.second < _Right.second);
    

    编辑:正如一些人指出的那样,如果您从标准库中窃取代码以在您的代码中使用,您应该重命名前面带有下划线的内容,因为这些名称是保留的。

    【讨论】:

    • 当然,您实际上不应该使用该代码(至少不首先重命名变量)。前导下划线在标准库之外是不好的。
    • 中肯的评论,我只是不假思索地粘贴了它。反对剪切和粘贴代码的好论据!
    • +1。这样做的好处是只需要 LessThanComparable 行为,而不是额外需要许多其他答案中隐含的 EqualityComparable 概念。
    • 并非所有前面有下划线的东西总是被保留。 _Leadingcapitals 总是如此,就像在这种情况下一样。任何包含double__underscores 的标识符也是如此。但是,_leadinglowercase 仅保留在全局范围内(不过我认为它也不值得在其他地方使用)。
    【解决方案4】:

    基本流程应该是这样的:如果第 K 个元素不同,则返回较小的,否则转到下一个元素。以下代码假设您没有有一个 boost 元组,否则您将使用 get&lt;N&gt;(tuple) 并且一开始就没有问题。

    if (lhs.first != rhs.first)
        return lhs.first < rhs.first;                
    if (lhs.second != rhs.second)
        return lhs.second< rhs.second;
    return lhs.third < rhs.third;
    

    【讨论】:

      【解决方案5】:

      严格的弱排序

      这是一个定义两个对象之间关系的数学术语。
      它的定义是:

      如果 f(x, y) 和 f(y, x) 都为假,则两个对象 x 和 y 是等价的。请注意,一个对象总是(通过非自反不变量)等价于它自己。

      就 C++ 而言,这意味着如果您有两个给定类型的对象,则在与运算符 <.> 进行比较时,您应该返回以下值

      X    a;
      X    b;
      
      Condition:                  Test:     Result
      a is equivalent to b:       a < b     false
      a is equivalent to b        b < a     false
      
      a is less than b            a < b     true
      a is less than b            b < a     false
      
      b is less than a            a < b     false
      b is less than a            b < a     true
      

      如何定义等效/更少完全取决于对象的类型。

      正式定义:
      Strict Weak ordering

      计算机科学:
      Strict Weak Ordering

      它与运营商的关系:
      Comparator


      作为旁注,我们可以手动实现严格的弱排序。但是我们可以简单地使用为您实现它的std::tuple 来完成它。您只需要创建一个元组而不复制对象。

      struct S
      {
           ThingA   a;
           ThingB   b;
      };
      bool operator<(S const& lhs, S const& rhs)
      {
          return std::tie(lhs.a, lhs.b) < std::tie(rhs.a, rhs.b);
      }
      

      注意:这里假设 thingAthingB 自己已经实现了严格的弱排序。

      我们也可以用同样的方式实现相等:

      bool operator==(S const& lhs, S const& rhs)
      {
          return std::tie(lhs.a, lhs.b) == std::tie(rhs.a, rhs.b);
      }
      

      再次注意:这假设thingAthingB 已经实现了相等性。

      【讨论】:

      • 我读过的关于严格弱序的最佳解释。我喜欢你通过详尽地解释所有案例来非​​常清楚
      • 特别是帮助我理解如何建立严格的弱排序的是等价是如何由ab 确定的,从不小于另一个。这正是我的比较器谓词中存在错误的地方。
      【解决方案6】:

      ...对一个非常老问题的新答案,但现有答案错过了 C++11 的简单解决方案...

      C++11解决方案

      C++11 及更高版本提供std::tuple&lt;T...&gt;,您可以使用它来存储数据。 tuples 有一个匹配的 operator&lt;,它最初比较最左边的元素,然后沿着元组工作,直到结果清晰。这适用于提供例如预期的strict weak orderingstd::setstd::map

      如果您在其他变量中有数据(例如 struct 中的字段),您甚至可以使用 std::tie() 创建一个引用元组,然后可以将其与另一个类似的元组。这使得为​​用户定义的class/struct 类型中的特定成员数据字段编写operator&lt; 变得容易:

      struct My_Struct
      {
          int a_;
          double b_;
          std::string c_;
      };
      
      bool operator<(const My_Struct& lhs, const My_Struct& rhs)
      {
          return std::tie(lhs.a_, lhs.b_, lhs.c_) < std::tie(rhs.a_, rhs.b_, rhs.c_);
      }
      

      【讨论】:

      • 我有更多关于如何使用成员tie() 函数来支持this answer 中多个运算符的简洁和一致版本的详细信息 - 但总结auto My_Struct::tie() const { return std::tie(a_, b_, c_); } 然后例如bool operator&lt;(const My_Struct&amp; lhs, const My_Struct&amp; rhs) { return lhs.tie() &lt; rhs.tie(); }(重复 &lt;=== 等)。当然 C++ 增加了3-way comparison,这是一个更好的选择。
      猜你喜欢
      • 1970-01-01
      • 2020-02-18
      • 2013-02-14
      • 2010-11-20
      • 2016-02-04
      • 1970-01-01
      • 2019-06-09
      • 2015-09-20
      • 2021-12-04
      相关资源
      最近更新 更多