尝试使用C qsort函数时出现问题

Lui*_*ndo 11 c qsort c89

#include <stdio.h>
#include <stdlib.h>

float values[] = { 4, 1, 10, 9, 2, 5, -1, -9, -2,10000,-0.05,-3,-1.1 };

int compare (const void * a, const void * b)
{
    return ( (int) (*(float*)a - *(float*)b) );
}

int main ()
{

    int i;

    qsort (values, 13, sizeof(float), compare);

    for (i = 0; i < 13; i++)
    {
        printf ("%f ",values[ i ]);
    }
    putchar('\n');

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

结果是:

-9.000000 -3.000000 -2.000000 -1.000000 -1.100000 -0.050000 1.000000 2.000000 4.000000 5.000000 9.000000 10.000000 10000.000000

这是错误的,因为-1和-1.1的顺序被改变了.我相信它正在发生,因为我的"比较"功能.

我怎样才能解决这个问题?

谢谢

AnT*_*AnT 36

您的比较功能已损坏.例如,它表示-1.0等于(等价)-1.1,因为它(int) ((-1.0) - (-1.1))是零.换句话说,你自己告诉qsort相对顺序-1.0-1.1无关紧要.为什么你感到惊讶的是,在结果排序中这些值没有排序?

通常,您应该避免通过从一个减去另一个来比较数值.它只是不起作用.对于浮点类型,由于很多不同的原因,它可能会产生不精确的结果,其中一个原因就是您自己观察到的.对于整数类型,它可能会溢出.

比较两个数值通用成语abqsort看起来(a > b) - (a < b).记住它并使用它.在你的情况下,将是

int compare (const void * a, const void * b)
{
  float fa = *(const float*) a;
  float fb = *(const float*) b;
  return (fa > fb) - (fa < fb);
}
Run Code Online (Sandbox Code Playgroud)

在C代码中,定义宏可能非常有意义

#define COMPARE(a, b) (((a) > (b)) - ((a) < (b)))
Run Code Online (Sandbox Code Playgroud)

并使用它而不是明确地拼写出比较.

  • +1需要更多的加号,这需要被接受作为答案. (2认同)
  • @chux:在执行`(fa> fb) - (fa <fb)`时,只有低质量的编译器会执行两次比较.大多数CPU通过使用设置某些CPU状态标志的CPU指令来比较值.这些状态标志完整地描述了比较的结果.单个`fa与fb`比较生成的标志涵盖了`fa`和`fb`之间的所有关系比较.即一个比较立即给你'fa> fb`和`fa <fb`的答案.所需要的只是从CPU标志中提取这些结果并执行减法. (2认同)

rus*_*lik 1

通过将差值四舍五入到整数,您会失去精度。

编辑:

将比较函数修改为

return (*(float*)a >= *(float*)b) ? 1 : -1;

编辑 AndreyT:我不认为只返回1or-1会导致无限循环或不正确的排序(它只会交换不需要的相等值)。

具有明确的返回情况0将花费额外的浮点计算,并且它们很少相等。因此,如果输入数据中的冲突率很小,则可以省略相等性比较。

  • 您的编辑没有改变任何内容,只是现在相等的值将始终返回“1”。标准“qsort”是为三值函数的比较器设计的。无论您做什么,通常都不可能将其简化为二值函数。你必须返回“-1,0,+1”。 (2认同)