简体   繁体   English

为什么 qsort 不起作用,同时对结构数组进行排序

[英]Why qsort doesn't work, while sorting an array of structures

I have an array of such structs我有一个这样的结构数组

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

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

type can be 'i' or 'd' , depending on either integer or double value is stored in union field. type 可以是'i''d' ,取决于 integer 或双精度值存储在联合字段中。 The array looks as following:该数组如下所示:

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

The main thing, is that integers and doubles go one by one.最主要的是,整数和双倍 go 一个一个。 I need to sort this array using qsort in next way: integers should be sorted from lower to higher and doubles vice versa.我需要使用 qsort 以下列方式对这个数组进行排序:整数应该从低到高排序,反之亦然。 I use the following function to compare:我用下面的function来比较:

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;
    }
}

It is assumed, that if the values in unions have different types, than it returns 0 without comparing, so such sequence, as int,double,int,double should be saved.假设,如果联合中的值具有不同的类型,则返回 0 而不进行比较,因此应保存 int,double,int,double 这样的序列。 But the result is following:但结果如下:

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

Why does it change doubles with integers, if it should return 0 in that case?如果在这种情况下它应该返回 0,为什么它会用整数改变双精度数?

If you need to preserve the original list's 'interlocked pattern' of int and double types, yet sort each set of int and double values, then you can't use the standard qsort function as is on the complete list.如果您需要保留原始列表的intdouble类型的“互锁模式”,但对每组intdouble值进行排序,那么您不能使用完整列表的标准qsort function。

However, what you can do is to separate the int and double entries into new lists, sort those separately, then merge the two sorted lists back into the original, taking either an int or double entry from the relevant sorted list, depending on the type of the entry in the original list.但是,您可以做的是将intdouble条目分离到新列表中,分别对它们进行排序,然后将两个排序列表合并回原始列表,从相关排序列表中获取intdouble条目,具体取决于类型原始列表中的条目。

Here's a possible implementation (using the compare function from your code unchanged – though you'd get better performance for large lists if you made two, type-specific, comparison functions for use with the separated lists):这是一个可能的实现(使用未更改的代码中的compare function ——尽管如果您创建两个特定类型的比较函数以用于分隔列表,您将获得更好的大型列表性能):

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;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM