如何比较结构

时间:2012-07-28 19:08:38

标签: c++

我很难正确设置比较。 以下是我的问题示例,我的代码错误地假定{1,2} = {2,1}:http://ideone.com/i7huL

#include <iostream>
#include <map>
using namespace std;

struct myStruct {
  int a;
  int b;
  bool operator<(const myStruct& rhs) const {
           return rhs.a < this->a && rhs.b < this->b;
  }
};


int main() {
       std::map  <myStruct, int> mymap ;
       myStruct m1={1,2};
       myStruct m2={2,1};
       mymap.insert(make_pair(m1,3));
       std::map<myStruct, int>::iterator it1 = mymap.find(m1);
       std::map<myStruct, int>::iterator it2 = mymap.find(m2);
       cout << it1->second << it2->second;
       // here it1->second=it2->second=3, although I would have expected it2 to be equal to map.end().
}

我可以使用||而不是&amp;&amp;,但我不确定这是正确的方法。我只想拥有运营商&lt;以这样的方式实现,我能够在我的地图中找到对象,而不会出现任何错误,就像我链接到的代码中的情况一样。

感谢。

7 个答案:

答案 0 :(得分:7)

是的,这个运算符实现没有多大意义。我建议:

  bool operator<(const myStruct& rhs) const {
      return rhs.a < this->a || (rhs.a == this->a && rhs.b < this->b);
  }

答案 1 :(得分:6)

bool operator<(const myStruct& rhs) const {
  if (a < rhs.a) return true;
  if (a == rhs.a) return b < rhs.b;
  return false;
}

如果您正在寻找对许多数据成员的概括,那么使用C ++ 11 std::tie就是一个很好的例子:

struct S {
    int n;
    std::string s;
    float d;
    bool operator<(const S& rhs) const {
        return std::tie(n, s, d) < std::tie(rhs.n, rhs.s, rhs.d);
    }
};

答案 2 :(得分:5)

问题是您的运营商没有定义strict weak ordering。仔细考虑一下{1,2}{2,1}的示例将如何落入您的运算符中。假设X = {1,2}Y = {2,1}

X&lt; Y'是1&lt; 2 AND 2&lt; 1?不,因此X不小于Y.

Y&lt; X?是2&lt; 1 AND 1&lt; 2?不,因此Y不小于X.

所以,如果X不小于Y,且Y不小于X,那还剩下什么?他们是平等的。

您需要选择结构中的一个成员,ab作为主要比较。如果主要比较结果相同,那么只有然后才能检查次要比较。就像你alphabetize什么时候一样。首先你检查第一个字母,只有它们相等,你才能继续下一个字母。 Hans Passant提供了一个例子。

这是您的运营商更严重的问题示例。我上面给出的那个不是必然坏,因为也许你想要 {1,2}被认为等于{2,1}。基本问题是通过这样的一组值进行裁剪:考虑X = {1,1}, Y = {1,2}, Z = {2,2}

对于你的算子,X最终小于Z,因为1小于2.但X出来等于Y,Y出来等于Z.为了遵守严格的弱排序,如果X = Y ,和Y = Z,那么X应该等于Z.但在这种情况并非如此。

答案 3 :(得分:3)

你问过关于四个int成员的概括,这里是我如何构建这样的代码以获得最大的清晰度。

bool operator<(const myStruct& rhs) const
{
  if (a < rhs.a)
    return true;
  if (a > rhs.a)
    return false;
  if (b < rhs.b)
    return true;
  if (b > rhs.b)
    return false;
  if (c < rhs.c)
    return true;
  if (c > rhs.c)
    return false;
  if (d < rhs.d)
    return true;
  if (d > rhs.d)
    return false;
  return false;
}

您可以根据需要轻松地为这么多数据成员扩展此类代码。

答案 4 :(得分:1)

最简单的解决方案使用std::tie来比较元组。

return std::tie(rhs.a, rhs.b) < std::tie(a, b);

这可以非常快速地简化为更多数据成员。

答案 5 :(得分:1)

我更喜欢通过比较相等的元素来写这个,直到找到两个不同的元素:

bool operator<(const myStruct& rhs) const {
    if (a != rhs.a)
        return a < rhs.a;
    if (b != rhs.b)
        return b < rhs.b;
    return false; // this and rhs are equal.
}

我发现这比使用||的混合编写单个表达式更清晰,更具扩展性和&amp;&amp; (根据@HansPassant),比@jahhaj的每次通过测试的方法更紧凑,导致return true;return false;。性能大致相同,除非您了解值的分布。有一个论点可以避免使用operator==()而只使用operator<(),但这只适用于您尝试编写最大通用模板代码的情况。

答案 6 :(得分:0)

问题是你需要知道你的结构代表什么。否则定义&lt;操作员会变得武断。其他人将无法给你一个合适的答案。举个例子,你的结构代表2D中一个点的cartisian坐标。在这种情况下,您可以定义一个有意义的排序运算符,例如距结构原点的距离。

,即距离d1 = this-&gt; a * this-&gt; a + this-&gt; b * this-&gt; b 距离d2 = rhs.a * rhs.a + rhs.b * rhs.b if(d1&lt; d2)   返回true; 其他   返回false;