在std::sort中,你可以提供第三个参数,这是它如何对列表进行排序的基础。如果你想让第一个参数先出现,那么就返回true。如果你想让第二个参数先出现,你就返回false。我遇到了一个问题,我的 predicate 函数被认为是一个“无效的比较器”,我已经把它缩小到它不满足以下要求的事实:
if arg1 == arg2, compare function MUST return false.
我曾经见过一些术语,比如std::sort要求“严格弱排序”。除了两个地方,我得到的关于这些主题的所有其他页面似乎都是技术论文,我看不懂。我能理解的是:
In weak ordering some elements "may be tied" with each other.
但对我来说这也是“偏序集”的含义,它是:
"there may be pairs of elements for which neither element precedes the other"
此外,我不明白“严格”在其中任何一个中意味着什么。
抛开我对序理论术语的困惑不谈,我的问题是,如果在比较函数中,参数1和参数2相等,并且在这种情况下,我不在乎哪个在另一个之前(任何一个在前面都会让我高兴),为什么我不能返回true以使参数1在前面?
我还想问我的程序是如何知道它是一个无效的比较器的,但后来我想它可能只是在比较函数返回true时检查arg1和arg2是否相等。
6条答案
按热度按时间nimxete21#
compare函数只是模拟了一个“小于”运算符。考虑一下
<
运算符是如何处理像int
这样的原始类型的:返回
true
意味着您希望a
在b
之前排序。因此,如果不是这种情况,则返回false
,因为您希望b
在a
之前排序,或者因为它们的顺序无关紧要。如果你在参数相等时返回
true
,那么你是说你希望a
在b
之前,你希望b
在a
之前,这是一个矛盾。pbossiut2#
1.从代码Angular 看
当elements count大于**_S_threshold**(STL中默认值为16)时,std::sort()会使用quicksort。
下面的代码是快速排序中的**__unguarded_partition**函数。
如果arg 1 == arg 2,compare函数返回true,那么**__first**迭代器将继续向右移动,程序将超出范围并导致coredump。
因此,如果arg 1 == arg 2,则比较函数必须返回false。
2.从算法逻辑Angular 看
如果比较函数使用运算符<=,则对于相等的值返回true。如果要测试10 B是否等于10A,则自然会使用比较功能。在这个例子中,这是运算符<=。Tt检查这个表达式是否为真:
10A和10 B都是10,所以10A <= 10 B显然是正确的。同样清楚地,10 B <= 10A。上述表达式因此简化为
这就简化为
这是完全错误的。也就是说,测试得出结论,IOA和IOB不等同,因此不相同。此外,任何相等值返回true的比较函数都会做同样的事情。根据定义,相等的值不是相等的!是不是很酷?
你还可以看到**<< Effective STL>>,Item 21:Always have comparison functions return false for equal values.**
vuktfyat3#
std::sort
使用的算法未指定。通过使用不符合标准要求的比较函数,您打破了算法的假设,并导致未定义的行为。看看这个噪声比较函数的输出会发生什么,它使用
<=
(不是有效的比较器) 而不是<
(有效)。http://coliru.stacked-crooked.com/a/34e4cef3280f3728
在输出中,我打印了一个递增的变量 (供参考,以指出算法何时失控),后跟第一个参数的值及其在向量中的位置,然后是第二个参数及其在向量中的位置。示例如下所示:
这意味着这是比较函数的第124次调用,它正在比较索引12处的值2和索引7处的值4。
事情从第37行开始变得疯狂
它比较我甚至没有插入到向量中的值(144,192等)以及向量范围之外的索引(在本例中为负索引)。
23c0lvtd4#
为了解释Benjamin Lindley的答案,考虑std::sort使用Hoare类型分区方案的快速排序的典型情况。使用compare(value,pivot)扫描左侧的values < pivot以进行比较,而使用compare(pivot,value)扫描右侧的values > pivot。请注意,快速排序分区可能依赖于这样的事实,即左扫描或右扫描在遇到值== pivot时停止,并且不会继续扫描该扫描上的pivot。如果用户提供的compare函数在这样的比较中返回true(当value == pivot时为true),则扫描可以继续超出正在排序的数组或向量的边界,这显然是Benjamin Lindley的测试用例中发生的情况。
jobtbby35#
不需要深入研究数学,只需要使用'<'运算符(如果愿意,也可以使用'>')就可以比较两个变量。然而,“<”通常用于解释“严格弱排序”和实现排序器。
这个想法基本上是在实际编程中,如果
a < b == false
和b < a == false
,那么a == b
。bqujaahr6#
TL;DR:为什么std::sort compare函数在参数相等时必须返回false?
它必须返回false,因为不需要对相等的参数进行排序。
说明
双向比较运算符函数检查是否要在第二个数字之前返回第一个数字。如果是,则返回
true
,如果不是,则返回false
。std::sort
和许多其他库函数使用这样的运算符函数。例如。
然而,当比较函数用作此类库函数中的参数时,此类库函数习惯上基于比较函数的
true
响应来“动作”。因此,特别是对于std::sort
,std::sort
会做一些事情(即。当参数为真时,执行重新排序)。所以一般来说,当比较函数用作std lib算法的参数时,如果算法希望它做一些事情,它应该返回
true
。反之亦然,当它不应该做任何事情时,它应该返回false
。