qsort 结构的多种类型字段的自定义比较函数
Custom compare function for qsort multiple types of fields of a struct
我正在尝试使用 qsort 根据字段对结构数组进行排序。我目前停留在如何创建 qsort 中使用的比较函数上。
结构定义:
struct data{
unsigned char feet;
double lock;
short stall;
short gain;
char show;
char country;
int king;
unsigned int bunch;
short strange;
long int tiger;
char win[9];
float ramp;
char sea;
unsigned int test;
short cave;
char pound;
float sofa;
};
排序顺序(按优先顺序):
win in descending order. -
stall in ascending order. -
sea in ascending order. -
pound in ascending order. -
ramp in ascending order. -
test in descending order. -
feet in ascending order. -
show in ascending order. -
sofa in descending order. -
cave in ascending order. -
king in ascending order. -
gain in descending order. -
strange in ascending order. -
country in descending order. -
lock in descending order. -
bunch in ascending order.
tiger in ascending order.
这是我试过的比较函数,但我似乎无法得到正确的结果,请根据优先级对所有字段进行排序:
int cmpStructs(const void *a1, const void *a2){
struct data *a = (struct data *)a1;
struct data *b = (struct data *)a2;
if(strcmp(a->win,b->win)>0){
return -1;
} else if (strcmp(a->wine,b->wine)<0){
return 1;
} else if(a->stall>b->stall){
return 1;
} else if(a->stall<b->stall){
return -1;
}
///continued if else statements for the rest of the fields
return 0;
};
好吧,首先,您将所有这些 else if
位过于复杂化了:
int cmpStructs(const void *a1, const void *a2){
struct data *a = (struct data *)a1;
struct data *b = (struct data *)a2;
// win, descending.
if (strcmp(a->win, b->win) > 0) return -1;
if (strcmp(a->win, b->win) < 0) return 1;
// stall, ascending.
if (a->stall > b->stall) return 1;
if (a->stall < b->stall) return -1;
// And so on, for each field.
return 0;
};
这样,您就可以轻松地注释掉比较“套件”的大块,从而依次测试每个字段。
您还可以考虑使用宏 meta-programming 来使其更容易和更易读,同时减少 error-prone 因为复杂性局限在宏中,例如(未经测试,但你应该明白了):
#define CMP_STR_ASC(s1, s2) \
if (strcmp(s1, s2) > 0) return -1; \
if (strcmp(s1, s2) < 0) return 1;
#define CMP_STR_DESC(s1, s2) CMP_STR_ASC(s2, s1)
#define CMP_VAL_ASC(v1, v2) \
if (v1 > v2) return -1; \
if (v1 < v2) return 1;
#define CMP_VAL_DESC(v1, v2) CMP_VAL_ASC(v2, v1)
int cmpStructs(const void *a1, const void *a2){
struct data *a = (struct data *)a1;
struct data *b = (struct data *)a2;
// Very simple rule set, based on the macros.
CMP_STR_DESC ( a->win, b->win )
CMP_VAL_ASC ( a->stall, b->stall )
CMP_VAL_ASC ( a->sea, b->sea )
CMP_VAL_ASC ( a->pound, b->pound )
CMP_VAL_ASC ( a->ramp, b->ramp )
CMP_VAL_DESC ( a->test, b->test )
CMP_VAL_ASC ( a->feet, b->feet )
CMP_VAL_ASC ( a->show, b->show )
CMP_VAL_DESC ( a->sofa, b->sofa )
CMP_VAL_ASC ( a->cave, b->cave )
CMP_VAL_ASC ( a->king, b->king )
CMP_VAL_DESC ( a->gain, b->gain )
CMP_VAL_ASC ( a->strange, b->strange )
CMP_VAL_DESC ( a->country, b->country )
CMP_VAL_DESC ( a->lock, b->lock )
CMP_VAL_ASC ( a->bunch, b->bunch )
CMP_VAL_ASC ( a->tiger, b->tiger )
return 0;
};
只要你不做一些愚蠢的事情,比如将这些宏包装在没有大括号的 if/while
语句中,或者传入有副作用的参数,它们应该没问题(function-like 宏通常需要如果您希望能够在任何地方使用它们,则可以保护它们,但是,如果您只是将它们用作“独立”语句,则可以使用更简单的语句。
事实上,正是这种对宏的复杂性的隔离使得针对问题进行调整变得容易,例如 DevSolar 在评论中提出的问题(运行 strcmp
两次)。
由于隔离,您只需将宏更改为类似以下内容即可轻松解决此问题:
#define CMP_STR_ASC(s1, s2) { \
int cmpVal = strcmp(s1, s2); \
if (cmpVal > 0) return -1; \
if (cmpVal < 0) return 1; \
}
我正在尝试使用 qsort 根据字段对结构数组进行排序。我目前停留在如何创建 qsort 中使用的比较函数上。
结构定义:
struct data{
unsigned char feet;
double lock;
short stall;
short gain;
char show;
char country;
int king;
unsigned int bunch;
short strange;
long int tiger;
char win[9];
float ramp;
char sea;
unsigned int test;
short cave;
char pound;
float sofa;
};
排序顺序(按优先顺序):
win in descending order. -
stall in ascending order. -
sea in ascending order. -
pound in ascending order. -
ramp in ascending order. -
test in descending order. -
feet in ascending order. -
show in ascending order. -
sofa in descending order. -
cave in ascending order. -
king in ascending order. -
gain in descending order. -
strange in ascending order. -
country in descending order. -
lock in descending order. -
bunch in ascending order.
tiger in ascending order.
这是我试过的比较函数,但我似乎无法得到正确的结果,请根据优先级对所有字段进行排序:
int cmpStructs(const void *a1, const void *a2){
struct data *a = (struct data *)a1;
struct data *b = (struct data *)a2;
if(strcmp(a->win,b->win)>0){
return -1;
} else if (strcmp(a->wine,b->wine)<0){
return 1;
} else if(a->stall>b->stall){
return 1;
} else if(a->stall<b->stall){
return -1;
}
///continued if else statements for the rest of the fields
return 0;
};
好吧,首先,您将所有这些 else if
位过于复杂化了:
int cmpStructs(const void *a1, const void *a2){
struct data *a = (struct data *)a1;
struct data *b = (struct data *)a2;
// win, descending.
if (strcmp(a->win, b->win) > 0) return -1;
if (strcmp(a->win, b->win) < 0) return 1;
// stall, ascending.
if (a->stall > b->stall) return 1;
if (a->stall < b->stall) return -1;
// And so on, for each field.
return 0;
};
这样,您就可以轻松地注释掉比较“套件”的大块,从而依次测试每个字段。
您还可以考虑使用宏 meta-programming 来使其更容易和更易读,同时减少 error-prone 因为复杂性局限在宏中,例如(未经测试,但你应该明白了):
#define CMP_STR_ASC(s1, s2) \
if (strcmp(s1, s2) > 0) return -1; \
if (strcmp(s1, s2) < 0) return 1;
#define CMP_STR_DESC(s1, s2) CMP_STR_ASC(s2, s1)
#define CMP_VAL_ASC(v1, v2) \
if (v1 > v2) return -1; \
if (v1 < v2) return 1;
#define CMP_VAL_DESC(v1, v2) CMP_VAL_ASC(v2, v1)
int cmpStructs(const void *a1, const void *a2){
struct data *a = (struct data *)a1;
struct data *b = (struct data *)a2;
// Very simple rule set, based on the macros.
CMP_STR_DESC ( a->win, b->win )
CMP_VAL_ASC ( a->stall, b->stall )
CMP_VAL_ASC ( a->sea, b->sea )
CMP_VAL_ASC ( a->pound, b->pound )
CMP_VAL_ASC ( a->ramp, b->ramp )
CMP_VAL_DESC ( a->test, b->test )
CMP_VAL_ASC ( a->feet, b->feet )
CMP_VAL_ASC ( a->show, b->show )
CMP_VAL_DESC ( a->sofa, b->sofa )
CMP_VAL_ASC ( a->cave, b->cave )
CMP_VAL_ASC ( a->king, b->king )
CMP_VAL_DESC ( a->gain, b->gain )
CMP_VAL_ASC ( a->strange, b->strange )
CMP_VAL_DESC ( a->country, b->country )
CMP_VAL_DESC ( a->lock, b->lock )
CMP_VAL_ASC ( a->bunch, b->bunch )
CMP_VAL_ASC ( a->tiger, b->tiger )
return 0;
};
只要你不做一些愚蠢的事情,比如将这些宏包装在没有大括号的 if/while
语句中,或者传入有副作用的参数,它们应该没问题(function-like 宏通常需要如果您希望能够在任何地方使用它们,则可以保护它们,但是,如果您只是将它们用作“独立”语句,则可以使用更简单的语句。
事实上,正是这种对宏的复杂性的隔离使得针对问题进行调整变得容易,例如 DevSolar 在评论中提出的问题(运行 strcmp
两次)。
由于隔离,您只需将宏更改为类似以下内容即可轻松解决此问题:
#define CMP_STR_ASC(s1, s2) { \
int cmpVal = strcmp(s1, s2); \
if (cmpVal > 0) return -1; \
if (cmpVal < 0) return 1; \
}