Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 当参数相等时,为什么std::sort compare函数必须返回false?_C++_Sorting_Std - Fatal编程技术网

C++ 当参数相等时,为什么std::sort compare函数必须返回false?

C++ 当参数相等时,为什么std::sort compare函数必须返回false?,c++,sorting,std,C++,Sorting,Std,在std::sort中,您可以提供第三个参数,它是如何对列表进行排序的基础。如果希望第一个参数先出现,则返回true。如果希望第二个参数先出现,则返回false。我遇到了一个问题,即我的谓词函数被认为是一个“无效的比较器”,并且我已经将其缩小到不满足以下要求的事实: if arg1 == arg2, compare function MUST return false. 我见过一些术语,比如std::sort要求“严格弱排序”。除了两个地方,我得到的关于这些主题的所有其他页面似乎都是技术论文,

在std::sort中,您可以提供第三个参数,它是如何对列表进行排序的基础。如果希望第一个参数先出现,则返回true。如果希望第二个参数先出现,则返回false。我遇到了一个问题,即我的谓词函数被认为是一个“无效的比较器”,并且我已经将其缩小到不满足以下要求的事实:

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先出现


我还想问我的程序如何知道它是一个无效的比较器,但我想它可能只是检查arg1和arg2在比较函数返回true时是否相等。

比较函数只是模拟了一个“小于”运算符。考虑< <代码> 不深入数学,2个变量可以用“如果你愿意”来比较。但是,未指定
std::sort
使用的算法。通过使用不符合标准设置的要求的比较函数,您打破了算法的假设,并导致未定义的行为


< >看看在这个嘈杂的比较函数的输出中会发生什么,使用<代码> < P>解释Benjamin Lindley的答案,考虑STD::排序使用HORE类型分区方案的Quasr排序的典型情况。使用compare(value,pivot)扫描左侧的值pivot。请注意,快速排序分区可能依赖于这样一个事实:当左或右扫描遇到值==pivot时,它会停止,并且不会继续扫描该扫描上的pivot。如果用户提供的比较函数在这样的比较中返回true(value==pivot时为true),则扫描可以继续超出正在排序的数组或向量的边界,这显然是Benjamin Lindley的测试用例中发生的情况。

当元素计数大于\u s_阈值时(在STL中,默认值为16),std::sort()将使用快速排序

下面的代码是quicksort中的无保护分区函数

  /// This is a helper function...
  template<typename _RandomAccessIterator, typename _Tp, typename _Compare>
    _RandomAccessIterator
    __unguarded_partition(_RandomAccessIterator __first,
             _RandomAccessIterator __last,
             const _Tp& __pivot, _Compare __comp) 
   {
      while (true)
      {
        while (__comp(*__first, __pivot))
          ++__first;
        --__last;
        while (__comp(__pivot, *__last))
          --__last;
        if (!(__first < __last))
          return __first;
        std::iter_swap(__first, __last);
        ++__first;
      }
    }
所以,若arg1==arg2,则compare函数必须返回false


您还可以看到>,Item21:总是让比较函数为相等值返回false。

请注意,没有检查来验证您的比较器是否满足严格弱排序的要求。@raket1111:这是什么意思?如果实现愿意,可以自由地执行此类检查。事实上,一些现实生活中的实现确实做到了这一点。在我的VisualStudio中,它抛出一个异常,称为“无效的比较器”。我假设要么它显式地检查,要么排序算法中出现了错误并抛出它。@AnT真的吗?我的意思是,在一些实现中(比如gcc/clang),他们只是假设需求已经满足,如果没有满足,那么你会得到一些奇怪的顺序。@Rakete1111:不一定。如果未满足要求,则行为未定义。在现实生活中,它可以以多种方式表现出来,而不仅仅限于“某种奇怪的秩序”。它也很容易导致越界访问。为了防止这种情况,需要额外的检查,而AFAIK GCC/Clang并没有执行这些检查。所以我假设你观察到的那些“奇怪的命令”纯粹是运气造成的。在现实生活中,它也可能因为越界访问而崩溃。我不知道为什么这意味着我想要它。这是因为在下一步中,比较将基于相同的值,只是它们将被发送到参数相反的比较函数?@Zebrafish:这是定义上的。你似乎有点倒退:你不能按照你想要的方式实现它,然后告诉算法如何使用它——算法说“给我一个严格的排序谓词”,然后你实现它。在严格的排序中,当a==a时,f(a,a)==false。将比较改为

124: 2@12 <= 4@7
37: 0@0 <= 0@-1
38: 0@0 <= 144@-2
39: 0@0 <= 0@-3
40: 0@0 <= 192@-4
  /// This is a helper function...
  template<typename _RandomAccessIterator, typename _Tp, typename _Compare>
    _RandomAccessIterator
    __unguarded_partition(_RandomAccessIterator __first,
             _RandomAccessIterator __last,
             const _Tp& __pivot, _Compare __comp) 
   {
      while (true)
      {
        while (__comp(*__first, __pivot))
          ++__first;
        --__last;
        while (__comp(__pivot, *__last))
          --__last;
        if (!(__first < __last))
          return __first;
        std::iter_swap(__first, __last);
        ++__first;
      }
    }
while (__comp(*__first, __pivot))
    ++__first;