繁体   English   中英

在C中对结构数组进行排序

[英]Sorting an array of structures in C

假设我有这样的结构:

typedef struct MyStruct{
  char *string1;
  int number1, number2, number3;
  char string2[11], string3[9];
  char *string4;
  char *string5;
}MyStruct;

程序提示用户选择应该对数据进行排序的字段。 我无法想到一种有效排序数组的方法。 我真的需要为每个字段编写单独的排序函数吗? 必须有其他一些方法,因为编写8个函数,其中2就足够了,看起来不合理。

<stdlib.h>查找qsort() 它需要一个比较器功能。 您可以为不同的排序顺序编写单独的比较器函数,但仍使用标准库qsort()进行排序。

例如:

int ms_cmp_string1(const void *vp1, const void *vp2)
{
    const MyStruct *ms1 = vp1;
    const MyStruct *ms2 = vp2;

    int cmp = strcmp(ms1->string1, ms1->string2);
    if (cmp != 0)
        return cmp;
    else if (ms1->number1 < ms2->number1)
        return -1;
    else if (ms1->number1 > ms2->number1)
        return +1;
    //...other comparisons as required...
    else
        return 0;
}

对于比较器来说,这是一个不错的大纲。 这个在string1排序,然后在number1上排序。 您可以编写在不同字段上排序的变体,也可以设计一个按您选择的顺序应用各种可能测试的方案。 但基本大纲工作得很好,适合传递给qsort()而不需要任何强制转换。

如果只需要2个,则不需要编写8个函数。 构建自己的qsort函数并将包含成员偏移量的最后一个参数发送到compare函数,然后在compare函数中,将指针+偏移量转换为正确的类型。

就像是:

int comp_int(const void *pa, const void *pb, size_t offset)
{
    const int *a = (const int *)((const char *)pa + offset);
    const int *b = (const int *)((const char *)pb + offset);

    return *a - *b;
}

int comp_string(const void *pa, const void *pb, size_t offset)
{
    const char *a = (const char *)pa + offset;
    const char *b = (const char *)pb + offset;

    return strcmp(a, b);
}

void swap(void *v[], int a, int b)
{
    void *temp;

    temp = v[a];
    v[a] = v[b];
    v[b] = temp;
}

void sort(void *v[], int left, int right, size_t offset, int (*comp)(const void *, const void *, size_t))
{
    int i, last;

    if (left >= right) return;
    swap(v, left, (left + right) / 2);
    last = left;
    for (i = left + 1; i <= right; i++) {
        if ((*comp)(v[i], v[left], offset) < 0)
            swap(v, ++last, i);
    }
    swap(v, left, last);
    sort(v, left, last - 1, offset, comp);
    sort(v, last + 1, right, offset, comp);
}

offsetof可以帮助

以下是我在另一个答案中使用qsort的示例:

struct stringcase { char* string; void (*func)(void); };

void funcB1();
void funcAzA();

struct stringcase cases [] = 
{ { "B1", funcB1 }
, { "AzA", funcAzA }
};

struct stringcase work_cases* = NULL;
int work_cases_cnt = 0;

// comparator function
int stringcase_cmp( const void *p1, const void *p2 )
{
  return strcasecmp( ((struct stringcase*)p1)->string, ((struct stringcase*)p2)->string);
}

// prepare the data for searching
void prepare() {
  // allocate the work_cases and copy cases values from it to work_cases
  qsort( cases, i, sizeof( struct stringcase ), stringcase_cmp );
}

使用一些宏:

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

struct data {
    int x, y, z;
};

#define comp(member) comp_##member
#define comp_build(member)                          \
int comp_##member(const void *pa, const void *pb)   \
{                                                   \
    const struct data *a = pa, *b = pb;             \
    return (a->member < b->member)  ? -1 : (a->member > b->member); \
}

comp_build(x)
comp_build(y)
comp_build(z)

int main(void)
{
    #define ROWS 3

    struct data v[] = {
        {3, 2, 1},
        {1, 3, 2},
        {2, 1, 3}
    };
    int i;

    puts("Unsorted");
    for (i = 0; i < ROWS; i++) printf("%d %d %d\n", v[i].x, v[i].y, v[i].z);
    qsort(v, ROWS, sizeof(struct data), comp(x));
    puts("Sorted by x");
    for (i = 0; i < ROWS; i++) printf("%d %d %d\n", v[i].x, v[i].y, v[i].z);
    puts("Sorted by y");
    qsort(v, ROWS, sizeof(struct data), comp(y));
    for (i = 0; i < ROWS; i++) printf("%d %d %d\n", v[i].x, v[i].y, v[i].z);
    puts("Sorted by z");
    qsort(v, ROWS, sizeof(struct data), comp(z));
    for (i = 0; i < ROWS; i++) printf("%d %d %d\n", v[i].x, v[i].y, v[i].z);

    return 0;
}

如果你正在使用GNU C库,那么有一个名为qsort_r()的扩展,它允许你将一个额外的参数传递给比较函数。

暂无
暂无

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

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