【发布时间】:2010-11-02 01:26:19
【问题描述】:
如何在 n 元组(例如在 3 元组)上定义 operator< 以满足 严格弱排序 概念?我知道 boost 库有正确定义 operator< 的元组类,但由于某些原因我不能使用它。
【问题讨论】:
-
请澄清:您是在谈论定义 operator
如何在 n 元组(例如在 3 元组)上定义 operator< 以满足 严格弱排序 概念?我知道 boost 库有正确定义 operator< 的元组类,但由于某些原因我不能使用它。
【问题讨论】:
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< 可用,我倾向于使用该模式
if (a1 != b1)
return a1 < b1;
if (a2 != b2)
return a2 < b2;
...
【讨论】:
std::lexographical_compare。
您可以简单地使用三元素向量,它已经适当地具有 operator
【讨论】:
即使你不能使用 boost 版本,你也应该可以修改代码。我从 std::pair 中删除了这个 - 我猜 3 元组会很相似。
return (_Left.first < _Right.first ||
!(_Right.first < _Left.first) && _Left.second < _Right.second);
编辑:正如一些人指出的那样,如果您从标准库中窃取代码以在您的代码中使用,您应该重命名前面带有下划线的内容,因为这些名称是保留的。
【讨论】:
_Leadingcapitals 总是如此,就像在这种情况下一样。任何包含double__underscores 的标识符也是如此。但是,_leadinglowercase 仅保留在全局范围内(不过我认为它也不值得在其他地方使用)。
基本流程应该是这样的:如果第 K 个元素不同,则返回较小的,否则转到下一个元素。以下代码假设您没有有一个 boost 元组,否则您将使用 get<N>(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;
【讨论】:
这是一个定义两个对象之间关系的数学术语。
它的定义是:
如果 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);
}
注意:这里假设 thingA 和 thingB 自己已经实现了严格的弱排序。
我们也可以用同样的方式实现相等:
bool operator==(S const& lhs, S const& rhs)
{
return std::tie(lhs.a, lhs.b) == std::tie(rhs.a, rhs.b);
}
再次注意:这假设thingA 和thingB 已经实现了相等性。
【讨论】:
a 和b 确定的,从不小于另一个。这正是我的比较器谓词中存在错误的地方。
...对一个非常老问题的新答案,但现有答案错过了 C++11 的简单解决方案...
C++11 及更高版本提供std::tuple<T...>,您可以使用它来存储数据。 tuples 有一个匹配的 operator<,它最初比较最左边的元素,然后沿着元组工作,直到结果清晰。这适用于提供例如预期的strict weak ordering。 std::set 和 std::map。
如果您在其他变量中有数据(例如 struct 中的字段),您甚至可以使用 std::tie() 创建一个引用元组,然后可以将其与另一个类似的元组。这使得为用户定义的class/struct 类型中的特定成员数据字段编写operator< 变得容易:
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<(const My_Struct& lhs, const My_Struct& rhs) { return lhs.tie() < rhs.tie(); }(重复 <=、== 等)。当然 C++ 增加了3-way comparison,这是一个更好的选择。