[英]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.