为什么 qsort 在对结构数组进行排序时不起作用
Why qsort doesn't work, while sorting an array of structures
我有一个这样的结构数组
typedef union value_
{
double d;
int i;
} value;
typedef struct number_
{
char type;
value val;
}number;
type 可以是 '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;
}
}
假设,如果联合中的值有不同的类型,那么returns 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
如果在那种情况下应该 return 0,为什么它会用整数更改双精度数?
如果您需要保留原始列表的 int
和 double
类型的 'interlocked pattern',但对每组 int
和 double
值进行排序,那么您不能在完整列表中按原样使用标准 qsort
函数 。
但是,您可以做的是将 int
和 double
条目分离到新列表中,分别对它们进行排序,然后将两个排序后的列表合并回原始列表,取 int
或 double
来自相关排序列表的条目,具体取决于原始列表中条目的类型。
这是一种可能的实现方式(使用代码中的 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;
}
我有一个这样的结构数组
typedef union value_
{
double d;
int i;
} value;
typedef struct number_
{
char type;
value val;
}number;
type 可以是 '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;
}
}
假设,如果联合中的值有不同的类型,那么returns 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
如果在那种情况下应该 return 0,为什么它会用整数更改双精度数?
如果您需要保留原始列表的 int
和 double
类型的 'interlocked pattern',但对每组 int
和 double
值进行排序,那么您不能在完整列表中按原样使用标准 qsort
函数 。
但是,您可以做的是将 int
和 double
条目分离到新列表中,分别对它们进行排序,然后将两个排序后的列表合并回原始列表,取 int
或 double
来自相关排序列表的条目,具体取决于原始列表中条目的类型。
这是一种可能的实现方式(使用代码中的 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;
}