使用qsort()对结构体数组中的双精度浮点数进行排序

3

我正在使用qsort()对结构体数组中的双精度值进行降序排序。我有以下代码:

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

typedef struct page {
   double val;
   int id;
} page;

int cmpfunc(const void *a, const void *b) {
  const page *pageA = (page*)a;
  const page *pageB = (page*)b;
  return -(pageA->val - pageB->val);
}

int main(void) {
  page array[5];
  int n;
  int i = 1;

for(n = 0; n < 5; n++) {
    array[n].id = i;
    i++;
}

array[0].val = 0.0608;
array[1].val = 0.2230; 
array[2].val = 0.1673;
array[3].val = 0.1442;
array[4].val = 0.2499;

printf("Before sorting\n");

for(n = 0; n < 5; n++) {
    printf("page id = %d, val = %lf \n", array[n].id, array[n].val);
}

qsort(array, 5, sizeof(page), cmpfunc);

printf("\nAfter sorting\n");

for(n = 0; n < 5; n++) {
    printf("page id = %d, val = %lf \n", array[n].id, array[n].val);
}

return 0;
}

我尝试使用qsort()来对整数进行排序,成功了。但是在尝试对双精度浮点数进行排序时,我的输出没有排序:
排序后:
页面ID = 2,值= 0.223000
页面ID = 3,值= 0.167300
页面ID = 4,值= 0.144200
页面ID = 5,值= 0.249900
页面ID = 1,值= 0.060800
我不确定为什么输出没有正确排序。我已经阅读了在线帖子,了解如何对结构体数组中的值进行排序,并且相信我的比较函数是正确的。如果有任何见解,将不胜感激。

注意:一种被各种编译器认可的常见代码习惯是 return (a > b) - (a < b);,可以创建高效的代码。 - chux - Reinstate Monica
2个回答

3

由于比较函数返回一个整数,-(pageA->val - pageB->val) 的结果会四舍五入。

转换至

if (pageA->val == pageB->val)
    return 0;
else if(pageA->val > pageB->val)
    return 1;
else
    return -1;

我相信我的比较函数是正确的。

这里有个技巧。如果你只是相信一个函数是正确的,那么就进行测试来确定。你通过打印结果验证了排序不起作用。你也可以打印比较函数的输出。


我读到过,当使用qsort()比较两个值'a'和'b'时,函数必须返回负值,如果'a'要放在'b'之前,返回正值,如果'a'要放在'b'之后,则返回零。如果'a'>'b',则比较函数将返回1,但是如果'a'<'b',则比较函数将返回0。我对'a'<'b'的情况感到困惑,因为在这种情况下,'a'将被放置在'b'之前,但是比较函数将返回0而不是-1。如果函数不返回-1,qsort()如何知道将'a'放在'b'之前? - ceno980
我修复了。是我疏忽了。 - klutt

2

我们可以看到数组正在排序(这些 ID 已经移动了)。而且 ID 和值仍然正确匹配,因此 qsort 正确地移动了数据(我们没有使用错误的 sizeof)。

因此,我们的问题必须是我们传递的比较函数。让我们来看一下:

int cmpfunc(const void *a, const void *b) {
  const page *pageA = (page*)a;
  const page *pageB = (page*)b;
  return -(pageA->val - pageB->val);
}

返回一个整数,我们正在比较双精度浮点数。 pageA->val - pageB->val 的结果是一个双精度浮点数,然后被舍入为一个int。 这意味着当它们不相等时,有时会四舍五入为零(表示相等)。
因此更好的方法是:
int cmpfunc(const void *a, const void *b) {
  const page *pageA = (page*)a;
  const page *pageB = (page*)b;
  if (pageA->val == pageB->val)
      return 0;
  else
      return (pageA->val > pageB->val ? 1 : -1);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接