【问题标题】:Need help using qsort with an array of structs使用带有结构数组的 qsort 需要帮助
【发布时间】:2011-08-31 14:55:24
【问题描述】:

现在,我看到了各种各样的例子,但我不明白它们的意思。

这是我的结构

typedef struct profile{
    char gender[1];
    double soc;
       . . .
} PROFILE;

soc 是我要排序的社会安全号码。

我知道您需要一个比较功能,但我不知道如何找到我需要的确切功能。

【问题讨论】:

  • double 似乎是社会安全号码的一种相当荒谬的类型。它应该是char [10](如果您想允许输入非严格数字值)或uint32_t
  • 不要让反对者打扰你。 double 可能并不理想,但对于保存 9 位整数值来说已经足够了。至少你不会遇到舍入分数表示的问题。
  • @Mark Ransom:我几乎不认为反对者是指出不正确的设计/代码的合适术语!社保号从什么时候开始有分数的了!
  • @Mark Ransom:我认为 Stack Overflow 中没有任何规则禁止主动提供与问题不直接相关的主题的建议。如果有的话,我已经违反了很多次了。另外,我不同意你的观点。双倍绝对是错误的。
  • @Mark Ransom:是的,它会起作用,但它没有多大意义,特别是当您查看美国 SSN 的验证要求时。顺便说一句,在英国相当于 SSN 的是 NI 编号,它实际上确实以两个字母开头。

标签: c arrays struct qsort


【解决方案1】:

您的Soc 几乎可以肯定不是double 类型,但无论如何,这里有一个比较函数需要返回的示例:

int compare(const void *p1, const void *p2)
{
    const struct profile *elem1 = p1;    
    const struct profile *elem2 = p2;

   if (elem1->soc < elem2->soc)
      return -1;
   else if (elem1->soc > elem2->soc)
      return 1;
   else
      return 0;
}

感谢您指出const void *.

这是一个完整的例子(存档):Sorting Structures with the C qsort() Function

【讨论】:

  • -1 因为你不能把它传递给qsort 没有一个毛茸茸的演员,参数应该是const,这可以更简单地写成return (int)(elem1-&gt;soc - elem2-&gt;soc);
  • @Mitch - 然后发布者使用了一个奇怪的编译器。但是你修复了你的代码,所以我撤回了我的反对票。
  • @ChrisLutz:simple 减法在一般情况下是不正确的。有关反例,请参阅我的答案。
  • MS 文章现在可以在jeffpar.github.io/kbarchive/kb/073/Q73853 找到,注意比较不使用 void 指针。
【解决方案2】:

比较器的严格版本采用两个常量 void 指针:

int compare(const void *v1, const void *v2)
{
    const struct profile *p1 = v1;
    const struct profile *p2 = v2;
    if (p1->gender > p2->gender)
        return(+1);
    else if (p1->gender < p2->gender)
        return(-1);
    else if (p1->soc > p2->soc)
        return(+1);
    else if (p1->soc < p2->soc)
        return(-1);
    else
        return(0);
}

这将首先比较性别字段,然后是 soc 字段。这就是您处理任何多部分比较的方式。

【讨论】:

  • 你的比较功能是性别歧视! (此外,soc 比较可以作为return (int)(p1-&gt;soc - p2-&gt;soc); 完成。如果 OP(明智地)将soc 的类型更改为int,则不需要强制转换。)
  • @Chris: au contraire - 我的功能非常优雅;女士们先于先生们,你不知道吗?只要不会溢出,减法机制就会起作用;比较机制无论如何都有效。
  • 通过研究最近的一个问题发现,我对@ChrisLutz 与他的代表的建议感到惊讶。为 JL +1。
【解决方案3】:

这是一个在 C 语言中使用 qsort 的示例

/* qsort example */
#include <stdio.h>
#include <stdlib.h>

typedef struct {
    int price;
    int id;
} order;
order list[6];
int i = 0;

int compare (const void * a, const void * b)
{

  order *orderA = (order *)a;
  order *orderB = (order *)b;

  return ( orderB->price - orderA->price );
}

int main ()
{
    srand ( time(NULL) );

    printf("Before sorting\n");
    for(i=0; i<6; i++){ 
        list[i].price = rand()%10;
        list[i].id = i; 
        printf ("Order id = %d Price = %d \n",list[i].id, list[i].price);           
    }
    printf("AFTER sorting\n");
    int n;
    qsort (list, 6, sizeof(order), compare);
    for (n=0; n<6; n++)
         printf ("Order id = %d Price = %d \n",list[n].id, list[n].price);          
    return 0;
}

希望对你有帮助

卡捷琳娜·迪米特里斯

(所有关于pitsi)

【讨论】:

  • 非常有帮助,尤其是compare()。 :)
  • 您的compare 函数不正确:价格之间的差异可能大于int 类型的范围。例如:-3INT_MAX 为不适合 int 类型的表达式生成 INT_MAX + 3,调用未定义的行为,并且在大多数当前硬件上计算为负数,尽管比较应该返回一个正数。
  • 这个顺序是从大到小。如果你想要相反,你只需要在返回表达式上更改 orderA 和 orderB,对吗?
  • 没错,你应该改成return(orderA-&gt;price - orderB-&gt;price)
  • return ( (*(order *)b).price &gt; (*(order *)a).price ? 1 : -1);简洁的一行可能更容易改顺序...
【解决方案4】:

要对数组进行排序,请使用qsort() 并传递一个比较函数。

下面是对price 成员的所有可能值产生正确结果的方法:

typedef struct profile {
    char gender[1];
    double soc;
    int price;
    ...
} PROFILE;

int compare_price(const void *a, const void *b) {
    const PROFILE *oa = a;
    const PROFILE *ob = b;

    return (oa->price > ob->price) - (oa->price < ob->price);
}

int compare_soc(const void *a, const void *b) {
    const PROFILE *oa = a;
    const PROFILE *ob = b;

    return (oa->soc > ob->soc) - (oa->soc < ob->soc);
}

注意事项:

  • 如果差值不适合 int 类型,则简单的值减法会产生不正确的结果。例如-2INT_MAX 不能与减法正确比较。它也不适用于浮点值。

  • 上述方法可用于所有可比较的类型,包括doubleNaN除外。

如果你想处理NaN,下面是如何在最后对它们进行分组:

#include <math.h>

int compare_soc_nan_at_the_end(const void *a, const void *b) {
    const PROFILE *oa = a;
    const PROFILE *ob = b;

    if (isnan(oa->soc)) {
        return isnan(ob->soc) ? 0 : 1;
    } else
    if (isnan(ob->soc)) {
        return -1;
    } else {
        return (oa->soc > ob->soc) - (oa->soc < ob->soc);
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多