严格的弱排序混乱



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

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。我需要定义运算符

struct cmpless
{
bool operator()(const Airport& left, const Airport& right)
{
//?
}
}; 
std::set<Airport, cmpless> airportSet;

一个机场"小于"另一个机场是没有意义的。只有当机场根据其统计数据相等时才有意义。

我如何确定我的运算符<定义将遵循严格的弱排序?在这种情况下,我如何开始考虑定义operator<?>

如果可能的话,带有解释的示例会很棒!

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

由于您不需要根据operator<()定义顺序,因此只需将Airport按某种顺序排列,以便将它们定位在std::set<Airport>中可能是合理的,这是通过使用与std::less<Airport>不同的比较函数对象来完成的。但是,您当前在Airport对象中的属性看起来并不像合适的键。事实上,它们看起来都是可变的,也就是说,你可能无论如何都不需要std::set<Airport>,因为你不能修改std::set<T>中的元素(好吧,至少,你不应该;是的,我意识到你可以和mutable玩弄,但这势必会破坏元素的顺序)。

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

也就是说,要在一组对象O上定义一个严格的弱序,你需要一个二元关系r(x, y)使得以下条件对元素xyOz成立:

  • 反身:r(x, x) == false
  • 不对称:r(x, y) == true意味着r(y, x) == false
  • 传递:r(x, y) == truer(y, z) == true意味着r(x, z) == true
  • 不可比性:r(x, y) == falser(y, x) == falser(y, z) == falser(z, y) == false意味着r(x, z) == falser(z, x) == false

前三个应该足够简单。最后一个一开始有点奇怪,但实际上也不是那么难:基本思想是关系不完全排序元素,而是将它们分组到等效的类中。如果你认为关系r"小于",它只是说如果x都不小于y也不小于y小于x,那么xy是等价的。无与伦比的元素只是等价的。

标准容器以严格的弱顺序工作,但例如,std::set<T>std::map<K, V>只保留一个版本的等效密钥。这已经足够了,这很好,但通常只使用一个总序更简单,这是一个严格的弱序,其中每对元素xyr(x, y) == truer(y, x) == true(但是,由于不对称性,不是两者兼而有之)。

在musingstudio博客上找到了一个不错的解决方案,并认为我在这里分享给下一个需要的解决方案(即使Dietmar可能是对的,地图不合适):

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;
}

如果每个成员都定义了<,则可以执行类似于字典顺序的操作:

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));
}
}; 

最新更新