在某种意义上,其他两个是隐含的,但更准确的说法是比较排序实际上不需要三值比较器,并且 C++ 的排序以不使用三值比较器的方式实现,以最小化比较器所需的行为。
std::sort 定义和专门使用这样的东西是错误的:
template <typename T, typename Cmp>
int get_tri_value(const T &a, const T &b, Cmp lessthan) {
if (lessthan(a,b)) return -1;
if (lessthan(b,a)) return 1;
return 0;
}
...因为在调用lessthan
. 如果您的算法对返回 1 和返回 0 之间的差异没有任何用处,那么您就浪费了比较。
C++ 指的是“严格的弱排序”。If<
是严格的弱排序,并且!(a < b) && !(b < a)
,它不一定遵循a == b
。它们只是在排序中“在同一个地方”,并且!(a < b) && !(b < a)
是等价关系。因此,sort
订单等价类对象所需的比较器不提供总订单。
它唯一的区别是你在什么时候说什么!(a < b)
。对于严格的总顺序,您会推断b <= a
,阅读“小于或等于”。对于严格的弱顺序,您不能定义b <= a
为意味着b < a || b == a
并使其为真。C++ 对此很迂腐,因为它允许运算符重载,所以它几乎必须如此,因为重载运算符的人需要行话来告诉用户他们的代码他们在运算符之间的关系方面可以期待什么。Java确实谈到了比较器和hashCode与equals一致,这就是你所需要的。C++ 必须处理 <、>、==、<=、>=、赋值的后置条件等等。
C++ 在 API 中对此采用了相当纯的数学方法,因此所有内容都根据单个二进制关系定义。Java 在某些方面更友好,并且更喜欢三路比较,其中基本单元的定义(比较)有点复杂,但由此得出的逻辑更简单。这也意味着排序算法每次比较都会获得更多信息,这有时很有用。例如,请参阅“荷兰国旗”快速排序优化,当数据中有很多“在同一个地方”重复时,这是一个好处。
在这种情况下,三值比较器是速度增益。set
但是 C++ 对 sort 和andmap
等使用了一致的比较器定义lower_bound
,这几乎没有从三值比较器中受益(可能保存一个比较,也可能没有)。我猜他们为了特定或有限的潜在效率收益而决定不使他们漂亮的通用界面复杂化。