【问题标题】:How does the compare function in qsort work?qsort 中的比较功能如何工作?
【发布时间】:2014-12-04 00:23:39
【问题描述】:

我在网上找到了这个示例代码,它解释了qsort 函数的工作原理。我无法理解比较函数返回的内容。

#include "stdlib.h"

int values[] = { 88, 56, 100, 2, 25 };

int cmpfunc (const void * a, const void * b) //what is it returning?
{
   return ( *(int*)a - *(int*)b ); //What is a and b?
}


int main(int argc, _TCHAR* argv[])
{

   int n;

   printf("Before sorting the list is: \n");
   for( n = 0 ; n < 5; n++ ) {
      printf("%d ", values[n]);
   }

   qsort(values, 5, sizeof(int), cmpfunc);

   printf("\nAfter sorting the list is: \n");
   for( n = 0 ; n < 5; n++ ) {
      printf("%d ", values[n]);
   }
    return 0;
}

【问题讨论】:

  • 它们是从数组values 中读取的整数。该函数返回a - b 的值,如果a 较小,则为&lt; 0(负数),如果相等,则为0,或&gt; 0(正数)如果 a 更大。
  • qsort 的比较函数(实际上是回调函数)返回与 strcmp() IE 完全相同的值。如果第一个项目小于第二个项目返回 -1 如果项目匹配返回 0 如果第一个项目大于第二个项目返回 1
  • @user3629249:注意不要测试特定值-11strcmp()(或传递给qsort()的比较函数)允许返回任何负数或正数这些情况的值。
  • 这个比较函数不好,永远不要使用它。假设,你正在排序-1500000000和1500000000。减法的结果是-3000000000,在@987654336中无法表示@,因此行为未定义。更糟糕的是,生成代码的通常行为是将其包装为一个正数 1294967296,这完全破坏了排序。 See AnT's answer for the one that works correctlythis QA for what can happen if you use this comparison function

标签: c quicksort


【解决方案1】:
int cmpfunc (const void * a, const void * b) //what is it returning?
{
   return ( *(int*)a - *(int*)b ); //What is a and b?
}

相当于:

int cmpfunc (const void * a, const void * b) //what is it returning?
{
   // qsort() passes in `void*` types because it can't know the actual types being sorted
   // convert those pointers to pointers to int and deref them to get the actual int values

   int val1 = *(int*)a;
   int val2 = *(int*)b;

   // qsort() expects the comparison function to return:
   // 
   //    a negative result if val1 < val2
   //    0 if val1 == val2
   //    a positive result if val1 > val2

   return ( val1 - val2 ); 
}

【讨论】:

【解决方案2】:

qsort 的文档中明确说明了 ab 是什么:它们是指向必须比较的数组元素的指针。

这种情况下的比较函数知道数组元素的类型为int。因此,它将void * 指针转换为int * 类型,并通过从第一个减去第二个值对指向的int 值执行三态比较。

它适用于您的一组值,但在一般情况下,使用减法进行三态比较是一种不好的编程习惯,因为它容易溢出。此外,示例代码中的函数不必要地丢弃了指向值的常量。

更好的选择是

int cmpfunc(const void *a, const void *b)
{
   const int *A = a, *B = b;
   return (*A > *B) - (*A < *B);
}

【讨论】:

    【解决方案3】:

    当排序算法需要找出两个元素中的哪一个应该放在另一个之前时,它会调用比较函数并传递指向这两个元素的指针。由于您正在对 int 值进行排序,因此指针实际上是指向 int 的指针,但签名必须采用 void* 以便它可以与任何数据类型一起使用。因此,为了获得实际的元素值,必须将a 强制转换为int*,然后取消引用——因此,*(int*)a。如果将a 放在b 之前,则该函数必须返回一个负值,如果将b 放在a 之前,则该函数必须返回一个正值,或者如果哪个放在第一个都无关紧要则返回零(哪个通常是元素相等时的情况)。在这种特殊情况下,由于我们处理的是数字,如果我们希望最大的数字先出现,只需从 a 的值中减去 b 的值就足够了。

    【讨论】:

      【解决方案4】:

      来自http://en.cppreference.com/w/cpp/algorithm/qsort

      如果第一个参数小于第二个参数,cmp 函数返回一个负整数值, 如果第一个参数大于第二个参数,则为正整数值;如果参数相等,则为 0。

      该函数采用void 指针,因此qsort 函数可用于任何数据类型。但是在 cmp 函数中,您必须将指针显式转换为实际数据类型。

      【讨论】:

        【解决方案5】:

        ab 被作为整数进行比较 - 它们必须作为 void * 传入,但然后在最终被尊重之前转换为 int *。至于返回值,可以是正数、负数或零,所有这些都会在排序函数中考虑。

        【讨论】:

          【解决方案6】:

          qsort 将给它需要比较的每一对与 cmpfunc 并使用它的返回值来查看哪个更大,然后对数组进行相应的排序。

          基本上,如果比较函数返回肯定结果,这意味着第一个参数大于第二个参数。同样,如果返回负数,则第二个参数更大。

          在示例中,我们要对整数进行排序。因此,当我们比较给定数组的两个元素时,我们需要确定哪个更大。为了比较它们,一个简单的减法运算就足够了,因为当 a 更大时结果为正,如果 a 和 b 相等则结果为 0,如果 b 更大则结果为负。

          【讨论】:

            猜你喜欢
            • 2013-11-02
            • 1970-01-01
            • 2019-09-03
            • 2011-12-02
            • 2022-11-04
            • 2017-07-29
            • 1970-01-01
            • 2020-11-20
            • 2022-06-16
            相关资源
            最近更新 更多