C语言 为什么qsort对相同的数组不同的排序产生不同的输出?



我试图在c中的qsort的帮助下按降序对数组进行排序。

#include<stdio.h>
#include<stdlib.h>
int compareFloat(const void* p1, const void* p2){
    const float* pa = p1;
    const float* pb = p2;
    return pb - pa;
}
int main()
{
    float arr[] = {1.5, 1.6, 1.38};
    qsort(arr, 3, sizeof(float), compareFloat);
    printf("%.2f %.2f %.2f", arr[0], arr[1], arr[2]);
    return 0;
}

上面代码的输出是"1.60 1.38 1.50",这是错误的;但是,当数组初始化为float arr[] = {1.38, 1.6, 1.5}时,答案是正确的(即"1.6,1.5,1.38")。

为什么?

在比较函数

int compareFloat(const void* p1, const void* p2){
    const float* pa = p1;
    const float* pb = p2;
    return pb - pa;
}

返回两个指针的差值。但是,您需要比较的是指向的值,而不是指针本身。

函数可以如下所示

int compareFloat( const void* p1, const void* p2)
{
    float a = *( const float * )p1;
    float b = *( const float * )p2;
    return ( a < b ) - ( b < a );
}

这是一个示范程序。

#include <stdio.h>
#include <stdlib.h>
int compareFloat( const void *p1, const void *p2 )
{
    float a = *( const float * )p1;
    float b = *( const float * )p2;
    return ( a < b ) - ( b < a );
}
int main( void )
{
    float arr[] = { 1.5, 1.6, 1.38 };
    const size_t N = sizeof( arr ) / sizeof( *arr );
    qsort( arr, N, sizeof( float ), compareFloat );
    printf( "%.2f %.2f %.2fn", arr[0], arr[1], arr[2] );
}

程序输出为

1.60 1.50 1.38

您的compareFloat函数的返回值是错误的…两个原因。

首先,您正在减去指针,而不是它们指向的值-因此您需要*pb - *pa

但是,即使这样,对于1.61.5这样的值,您的测试也会失败,因为减法的结果将是非零但小于1 。因此,当转换为int返回类型时,该函数将返回0(表示值是相同的),即使它们不是。

您需要返回至少两次比较的结果:

int compareFloat(const void* p1, const void* p2)
{
    const float* pa = p1;
    const float* pb = p2;
    return (*pa < *pb) - (*pa > *pb);
}

您的比较程序不正确。

return pb - pa;

你在这里减去两个指针的值。

如果处理的是整数,则应该减去指针所指向的数字:

return *pb - *pa;

但是由于小数部分被截断,这对浮点数不起作用。您需要显式地比较并返回正确的值。

if (*pa > *pb) {
    return -1;
} else if (*pa < *pb) {
    return 1;
} else {
    return 0;
}

有人指出了以下两点不足:

  • OP的指针减法应该是浮点FP减法/比较。

  • 结果需要为int

    int compareFloat(const void* p1, const void* p2){
      const float* pa = p1;
      const float* pb = p2;
      // return pb - pa;
      return (*pb > *pa) - (*pb < *pa);
    }
    

还有另一个问题:如果任意一个FP值可能是一个非数字NAN,则应用额外的关注来保持比较兼容。我们需要一个当参数反转时返回相反符号的排序。同样,如果a > bb > c,那么a > c。上面的(*pb > *pa) - (*pb < *pa)不能实现nan。

int compareFloat(const void* p1, const void* p2){
  const float f1 = *(const float *)p1;
  const float f2 = *(const float *)p2;
  if (isnan(f1)) {
    if (isnan(f2)) {
      // Since both are NA, just compare bit patterns
      return memcmp(p1, p2, sizeof (float));
    }
    return 1; // Consider NAN < all non-NANs
  }
  if (isnan(f2)) {
    return -1;
  }
  return (f2 > f1) - (f2 < f1);
}
int main() {
  float arr[] = {1.5f, 1.6f, NAN, 1.38f};  // Better to use float constants
  qsort(arr, 4, sizeof(float), compareFloat);
  printf("%.2f %.2f %.2f %.2f", arr[0], arr[1], arr[2], arr[3]);
  return 0;
}

输出
1.60 1.50 1.38 nan

最新更新