严格的弱序排列混乱

时间:2012-11-27 00:14:48

标签: c++ operator-overloading set strict-weak-ordering

我对严格的弱排序以及在定义operator<时如何使用它感到困惑。我有几个结构:

struct Plane
{
    std::string name;

    int xrudder;
    int yrudder;

    int wingwidgets;

    bool hasLegacyEngine;
};


struct Airport
{
    bool securityCheck;
    unsigned __int64 capacity;

    std::vector<Plane> planes;
};

我想创建std::set个机场。我需要定义运算符&lt;它使用严格的弱排序,但我不确切地知道这意味着什么和/或如何做。

struct cmpless
{
bool operator()(const Airport& left, const Airport& right)
    {
        //?
    }
}; 

std::set<Airport, cmpless> airportSet;

一个机场“小于”另一个机场是没有意义的。只有机场根据他们的统计数据相等才有意义。

我怎样才能确定我对运算符的定义&lt;会遵循严格的弱序吗?如何在这种情况下开始考虑定义operator<

如果可能的话,一个解释的例子会很棒!

3 个答案:

答案 0 :(得分:5)

如果一个Airport在另一个Airport之前“没有意义”,那么使用std::set<Airport>也没有意义。此容器利用订单金额元素在O(log(n))操作中查找对象(其中n是容器的大小)。如果您只能通过标识识别对象,那么您可以实现的最佳复杂性是O(n)。您可以使用std::find()std::find_if()和其中一个序列容器的组合,例如std::vector<Airport>std::deque<Airport>

由于您不需要根据operator<()定义订单,因此将Airport置于某个顺序以便将其定位在{{1}中可能是合理的。这是通过使用与std::set<Airport>不同的比较函数对象来完成的。但是,您当前在std::less<Airport>对象中的属性看起来并不像合适的键。事实上,它们看起来都像是可变的,也就是说,你可能不会想要Airport,因为你无法修改std::set<Airport>中的元素(至少,你不应该;是的,我意识到你可以用std::set<T>玩弄技巧,但这必然会破坏元素的顺序。)

基于此,我建议使用mutablestd::map<std:string, Airport>用于识别机场,例如,使用std::string等机场代码来识别John F.纽约肯尼迪机场或伦敦希思罗机场"JFK"。方便的是,字符串上已经定义了严格的弱顺序。

也就是说,要在一组对象"LHR"上定义strict weak order,您需要一个二元关系O,以便以下条件适用于元素r(x, y),来自x的{​​{1}}和y

  • irreflexive:z
  • 非对称:O隐含r(x, x) == false
  • 及物性:r(x, y) == truer(y, x) == false暗示r(x, y) == true
  • 无法比较:r(y, z) == truer(x, z) == true以及r(x, y) == falser(y, x) == false隐含r(y, z) == falser(z, y) == false

前三个应该足够简单。最后一个有点奇怪,但实际上也不是那么难:基本思想是关系不完全对元素进行排序,而是将它们分组为等价的类。如果您认为关系r(x, z) == false“小于”它只是表示如果r(z, x) == false小于rx小于y ,然后yx是等效的。无与伦比的元素恰好相同。

标准容器使用严格的弱顺序,但例如xy只保留一个版本的等效键。很好,这是足够的,但通常使用一个严格弱顺序的总顺序更简单,其中每对元素std::set<T>std::map<K, V> x或{{ 1}}(但是,由于不对称而不是两者)。

答案 1 :(得分:1)

musingstudio blog上找到了一个很好的解决方案,并认为我在这里为下一个需要的人分享它(即使Dietmar可能是正确的,地图不合适):<​​/ p>

bool operator <(const T& rhs) const
{
  if (a < rhs.a)
    return true;
  else if (rhs.a < a)
    return false;

  if (b < rhs.b)
    return true;
  else if (rhs.b < b)
    return false;

  // repeat for all child elements c, d, e etc
  return false;
}

答案 2 :(得分:0)

如果每个成员都定义了<,你可以做类似于lexiographical命令的事情:

   struct cmpless
    {
    bool operator()(const Airport& left, const Airport& right)
        {
            return
              left.securityCheck < right.securityCheck
              || ((left.securityCheck == right.securityCheck
                   && left.capacity < right.capacity)
                  || (left.capacity == right.capacity
                      && left.planes < right.planes));
        }
    };