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

时间:2013-06-05 07:00:36

标签: c sorting

假设我有这样的结构:

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

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

5 个答案:

答案 0 :(得分:5)

qsort()查找<stdlib.h>。它需要一个比较器功能。您可以为不同的排序顺序编写单独的比较器函数,但仍然使用标准库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()而不需要任何演员阵容。

答案 1 :(得分:2)

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

int comp(const void *pa, const void *pb, unsigned long offset)
{
    const int *a = (const int *) (pa + offset);
    const int *b = (const int *) (pb + offset);

    return (*a > *b) - (*a < *b);
}

void swap(void *v[], int i, int j)
{
    void *temp;

    temp = v[i];
    v[i] = v[j];
    v[j] = temp;
}

void sort(void *v[], int left, int right, unsigned long offset, int (*comp)(const void *, const void *, unsigned long))
{
    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可以提供帮助

答案 2 :(得分:1)

以下是我的另一个答案中使用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 );
}

答案 3 :(得分:1)

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

答案 4 :(得分:0)

使用一些宏:

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

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