【问题标题】:Why qsort doesn't work, while sorting an array of structures为什么 qsort 不起作用,同时对结构数组进行排序
【发布时间】:2021-07-28 20:04:50
【问题描述】:

我有一个这样的结构数组

typedef union value_
    {
        double d;
        int i;
    } value;

typedef struct number_
{
    char type;
    value val;
}number;

类型可以是'i''d',取决于存储在联合字段中的整数或双精度值。 数组如下所示:

Integer value: -3
Double value: 4.84
Integer value: -4
Double value: 1.65
Integer value: 1
Double value: 2.54
Integer value: 2
Double value: -0.09

主要的是整数和双精度数一一对应。我需要使用 qsort 以下列方式对这个数组进行排序:整数应该从低到高排序,反之亦然。 我使用以下函数进行比较:

int compare(const void *A, const void *B){

    number *a = (number*)A;
    number *b = (number*)B;
    
    if (a->type == b->type) {
        if (a->type =='i') {
            return a->val.i - b->val.i;
        } else {
            if (a->val.d > b->val.d) return -1;
            if (a->val.d < b->val.d) return 1;
            else return 0;
        }
    } else {
        return 0;
    }
}

假设,如果联合中的值有不同的类型,则返回0而不进行比较,因此应该保存int,double,int,double这样的序列。但结果如下:

Integer value: -1
Integer value: -5
Double value: 0.20
Integer value: 2
Double value: -0.04
Double value: -2.69
Integer value: 4
Integer value: 5
Double value: 2.04
Integer value: 3

如果在这种情况下应该返回 0,为什么它会用整数更改双精度数?

【问题讨论】:

  • 由于您的compare 函数为两种不同类型返回equal,因此最终结果将是不可预测的。您可以更改它,使所有整数都低于所有双精度值,反之亦然。
  • 谢谢,我怀疑,这样比较是个坏主意
  • 我不认为你可以使用标准的qsort 函数来做你想做的事。如果您的compare 函数针对不同的类型返回0,那么正如@500-InternalServerError 所指出的那样,您有不可预测/未定义的行为;但是,如果您返回 +1-1,则 intdouble 类型将被打乱,以便它们在列表中是连续的,不是以他们最初的“交错”顺序。你需要自己的排序函数。
  • typedef struct number_ 更改为typedef struct number。没有理由添加下划线。
  • 来自 qsort 手册页:“如果两个成员比较相等,则它们在排序数组中的顺序未定义。”。我不认为您想要什么,您需要在结构中添加信息(数组中的结构位置)或使用其他排序函数来保留顺序

标签: c struct union qsort


【解决方案1】:

如果您需要保留原始列表的intdouble 类型的“互锁模式”,但对每组intdouble 值进行排序,那么您不能使用标准的qsort函数原样在完整列表中。

但是,您可以将 intdouble 条目分离到新列表中,分别对它们进行排序,然后将两个排序后的列表合并回原始列表中,采用 intdouble相关排序列表中的条目,具体取决于原始列表中条目的类型。

这是一个可能的实现(使用代码中的 compare 函数未更改 - 尽管如果您创建两个特定类型的比较函数用于分隔列表,您将获得更好的大型列表性能):

void printlist(number* list, size_t n)
{
    for (size_t i = 0; i < n; ++i) {
        if (list[i].type == 'i') printf("%d ", list[i].val.i);
        else printf("%lf ", list[i].val.d);
    }
    printf("\n");
}

int main()
{
    number list[] = {
        { 'i', { .i = -3} },   { 'd', { .d = 1.65} },
        { 'i', { .i = -4} },   { 'd', { .d = 4.85} },
        { 'i', { .i =  1} },   { 'd', { .d = -.09} },
        { 'i', { .i =  2} },   { 'd', { .d = 2.54} },
    };
    size_t Tcount = sizeof(list) / sizeof(*list), Icount = 0, Dcount = 0; // Counts for total, ints and doubles
    for (size_t i = 0; i < Tcount; ++i) {
        if (list[i].type == 'i') ++Icount;
        else ++Dcount;
    }
    // Display original list ...
    printlist(list, Tcount);
    number* Ilist = malloc(sizeof(number) * Icount);
    number* Dlist = malloc(sizeof(number) * Dcount);
    size_t Iindex = 0, Dindex = 0;
    // Separate lists ...
    for (size_t i = 0; i < Tcount; ++i) {
        if (list[i].type == 'i') Ilist[Iindex++] = list[i];
        else Dlist[Dindex++] = list[i];
    }
    // Sort each list separately ...
    qsort(Ilist, Icount, sizeof(number), compare);
    qsort(Dlist, Dcount, sizeof(number), compare);
    // Merge sorted lists ...
    Iindex = 0, Dindex = 0;
    for (size_t i = 0; i < Tcount; ++i) {
        if (list[i].type == 'i') list[i] = Ilist[Iindex++];
        else list[i] = Dlist[Dindex++];
    }
    // Display sorted list ...
    printlist(list, 8);
    // Clean up ...
    free(Ilist);
    free(Dlist);
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-21
    • 1970-01-01
    • 1970-01-01
    • 2021-04-07
    • 2014-07-04
    • 2021-05-08
    相关资源
    最近更新 更多