C - 混合 Qsort 与结构(字符串和双精度)
C - Mixed Qsort with Struct (String and Double)
我有一个几乎完整的代码,需要对一些东西进行 Qsort,首先我有整数数组、浮点数数组,然后我有带有 char 和 double 组合数组的结构。需要以某种方式对它们进行 qsort,但我卡住了。
这是我的代码,我对整数和浮点数排序没有问题,但我无法完成结构排序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 20
typedef struct product
{
double price;
char name[LEN];
} product;
int ComparFuncInt(const void *x, const void *y);
int ConparFuncFloat(const void *x, const void *y);
int ComparFuncStructName(const void *x, const void *y);
int ComparFuncStructPrice(const void *x, const void *y);
/* void PrintIntegerArray(int *numbers, int len);
void PrintFloatArray(float *numbers, int len);
void PrintStructArray(product *items, int len);
*/
int main(void)
{
unsigned option;
/* initialized variables to be used with functions */
int numArr1[] = {15, 25, 3, 19, 22, 17, -54, 0, 9};
float numArr2[] = {76.40f, 11.2f, 235.4f, 76.50f, 341.6f};
product prices[] = {{0.75f, "Milk"}, {0.99f, "Yogurt"}, {3.19f, "Cucumber"},
{1.09f, "Orange"}, {0.80f, "Bread"}, {0.99f, "Juice"}};
int numCount = sizeof(numArr1) / sizeof(int);
float floatCount = sizeof(numArr2) / sizeof(float);
double doubleCount = sizeof(struct product) / sizeof(double);
char charCount = sizeof(struct product) / sizeof(char);
while (1)
{
printf("\n\nSelect your action!\n\n");
printf("1. Sort integers (numArr1)\n");
printf("2. Sort decimals (numArr2)\n");
printf("3. Sort structures by price\n");
printf("4. Sort structures by name\n");
printf("0. Exit\n");
scanf("%u", &option);
switch (option)
{
case 1:
qsort(numArr1, (size_t)numCount, sizeof(int), ComparFuncInt);
for (int i = 0; i < numCount; printf("%3d", numArr1[i]), i++);
break;
case 2:
qsort(numArr2, (size_t)floatCount, sizeof(float), ConparFuncFloat);
for (int j = 0; j < floatCount; printf("%.2f ", numArr2[j]), j++);
break;
case 3:
qsort(prices, (size_t)doubleCount, sizeof(double), ComparFuncStructPrice);
for (int k = 0; k < doubleCount; printf("%.2f ", prices[k].price), k++);
break;
case 4:
qsort(prices, (size_t)charCount, sizeof(char), ComparFuncStructName);
for (int l = 0; l < charCount; printf("%s", prices[l].name), l++);
break;
case 0:
exit(1);
break;
default:
printf("Only selections from 1 to 4 and 0 are accepted\n");
}
}
return EXIT_SUCCESS;
}
int ComparFuncInt(const void *x, const void *y){
if(* (int*)x > *(int*)y) return 1;
else if(* (int*)x < *(int*)y) return -1;
else return 0;
}
int ConparFuncFloat(const void *x, const void *y){
if(* (float *)x > *(float *)y) return 1;
else if(* (float *)x < *(float *)y) return -1;
else return 0;
}
int ComparFuncStructName(const void *x, const void *y){
const char *pa = *(const char**)x;
const char *pb = *(const char**)y;
return strcmp(pa,pb);
}
int ComparFuncStructPrice(const void *x, const void *y){
if(* (float *)x > *(float *)y) return 1;
else if(* (float *)x < *(float *)y) return -1;
else return 0;
}
我想这样做,当用户选择 3 时,它会按价格对产品下的 PRICES 数组进行排序,如果用户选择 4,它应该按名称排序,在这两种情况下它都应该输出价格和名称,只是排序的差异。
在比较函数中,指针(x
和 y
在你的例子中)是指向数组元素的指针。如果数组是 int
,那么它是指向 int
的指针(即 int *
)。如果它是一个结构数组,那么它们是指向 结构 的指针(例如 product *
)。
要访问结构的成员,您当然需要使用正确的结构指针访问,例如箭头运算符 ->
.
如果将指针保存在适当的变量中也会更容易,这样您就不必一直进行所有转换。事实上,如果您想将传递的数据用作指针而不是值,则根本不需要强制转换,因为 void *
可以隐式转换为几乎任何其他指针类型(函数指针除外)。
所以对于你的结构比较功能,你可以做例如
int ComparFuncStructName(const void *x, const void *y){
const product *a = x;
const product *b = y;
return strcmp(a->name, b->name);
}
或者当然,由于您正在对结构数组进行排序,数组的元素大小就是结构的大小,因此您也需要修复它:
qsort(prices, charCount, sizeof prices[0], ComparFuncStructName);
哦,你对结构中元素数量的计算也是错误的。公式为sizeof array / sizeof array[0]
。 总是。无论数组的类型或其元素如何。 sizeof
的结果是 always size_t
,因此您也应该将它用作所有 sizeof
操作的类型。
所以你需要做
size_t charCount = sizeof prices / sizeof prices[0];
关于一个不相关且更具风格的注释:不要将 printf
调用与 for
循环的增量表达式结合使用。这将使代码更难阅读、理解、遵循和(最重要的)维护。
改为将所有语句放在循环体中:
for (int l = 0; l < charCount; l++)
printf("%s", prices[l].name);
您也不需要为循环使用不同的迭代变量。它们对于自己范围内的循环是本地的,因此您可以对所有循环重复使用 i
。
改变这个:
qsort(prices, (size_t)doubleCount, sizeof(double), ComparFuncStructPrice);
至:
qsort(prices, 6, sizeof(prices[0]), ComparFuncStructPrice);
因为结构数组只有一个大小,无论您是想按名称还是按价格排序。此外,无论您想按名称还是按价格排序,数组中每个元素的大小都等于结构的大小。
类似于按名称排序。
另外,你的比较函数是错误的。首先,您需要将每个 void 指针转换为一个结构。那么,就需要使用struct的相关字段进行比较了。
对于价格比较,使用 less 和 more 运算符。如果简单地减去,会得到错误的结果。
将所有内容放在一起(并丢弃非结构数组),您将得到:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 20
typedef struct product
{
double price;
char name[LEN];
} product;
int ComparFuncStructName(const void *x, const void *y);
int ComparFuncStructPrice(const void *x, const void *y);
/*
void PrintStructArray(product *items, int len);
*/
int main(void)
{
unsigned option;
product prices[] = {{0.75f, "Milk"}, {0.99f, "Yogurt"}, {3.19f, "Cucumber"},
{1.09f, "Orange"}, {0.80f, "Bread"}, {0.99f, "Juice"}};
size_t pricesCount = sizeof prices / sizeof prices[0];
while (1)
{
printf("\n\nSelect your action!\n\n");
printf("3. Sort structures by price\n");
printf("4. Sort structures by name\n");
printf("0. Exit\n");
scanf("%u", &option);
switch (option)
{
case 3:
qsort(prices, pricesCount, sizeof(prices[0]), ComparFuncStructPrice);
for (size_t k = 0; k < pricesCount; printf("%f ", prices[k].price), k++);
break;
case 4:
qsort(prices, pricesCount, sizeof(prices[0]), ComparFuncStructName);
for (size_t l = 0; l < pricesCount; printf("%s ", prices[l].name), l++);
break;
case 0:
exit(1);
break;
default:
printf("Only selections from 1 to 4 and 0 are accepted\n");
}
}
return EXIT_SUCCESS;
}
int ComparFuncStructName(const void *x, const void *y){
const product* pa = (const product*) x;
const product* pb = (const product*) y;
return strcmp(pa->name, pb->name);
}
int ComparFuncStructPrice(const void *x, const void *y){
const product* pa = (const product*) x;
const product* pb = (const product*) y;
return (pa->price > pb->price) - (pa->price < pb->price);
}
输出(如果我选择按名称排序):
Select your action!
3. Sort structures by price
4. Sort structures by name
0. Exit
Bread Cucumber Juice Milk Orange Yogurt
Select your action!
3. Sort structures by price
4. Sort structures by name
0. Exit
我有一个几乎完整的代码,需要对一些东西进行 Qsort,首先我有整数数组、浮点数数组,然后我有带有 char 和 double 组合数组的结构。需要以某种方式对它们进行 qsort,但我卡住了。
这是我的代码,我对整数和浮点数排序没有问题,但我无法完成结构排序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 20
typedef struct product
{
double price;
char name[LEN];
} product;
int ComparFuncInt(const void *x, const void *y);
int ConparFuncFloat(const void *x, const void *y);
int ComparFuncStructName(const void *x, const void *y);
int ComparFuncStructPrice(const void *x, const void *y);
/* void PrintIntegerArray(int *numbers, int len);
void PrintFloatArray(float *numbers, int len);
void PrintStructArray(product *items, int len);
*/
int main(void)
{
unsigned option;
/* initialized variables to be used with functions */
int numArr1[] = {15, 25, 3, 19, 22, 17, -54, 0, 9};
float numArr2[] = {76.40f, 11.2f, 235.4f, 76.50f, 341.6f};
product prices[] = {{0.75f, "Milk"}, {0.99f, "Yogurt"}, {3.19f, "Cucumber"},
{1.09f, "Orange"}, {0.80f, "Bread"}, {0.99f, "Juice"}};
int numCount = sizeof(numArr1) / sizeof(int);
float floatCount = sizeof(numArr2) / sizeof(float);
double doubleCount = sizeof(struct product) / sizeof(double);
char charCount = sizeof(struct product) / sizeof(char);
while (1)
{
printf("\n\nSelect your action!\n\n");
printf("1. Sort integers (numArr1)\n");
printf("2. Sort decimals (numArr2)\n");
printf("3. Sort structures by price\n");
printf("4. Sort structures by name\n");
printf("0. Exit\n");
scanf("%u", &option);
switch (option)
{
case 1:
qsort(numArr1, (size_t)numCount, sizeof(int), ComparFuncInt);
for (int i = 0; i < numCount; printf("%3d", numArr1[i]), i++);
break;
case 2:
qsort(numArr2, (size_t)floatCount, sizeof(float), ConparFuncFloat);
for (int j = 0; j < floatCount; printf("%.2f ", numArr2[j]), j++);
break;
case 3:
qsort(prices, (size_t)doubleCount, sizeof(double), ComparFuncStructPrice);
for (int k = 0; k < doubleCount; printf("%.2f ", prices[k].price), k++);
break;
case 4:
qsort(prices, (size_t)charCount, sizeof(char), ComparFuncStructName);
for (int l = 0; l < charCount; printf("%s", prices[l].name), l++);
break;
case 0:
exit(1);
break;
default:
printf("Only selections from 1 to 4 and 0 are accepted\n");
}
}
return EXIT_SUCCESS;
}
int ComparFuncInt(const void *x, const void *y){
if(* (int*)x > *(int*)y) return 1;
else if(* (int*)x < *(int*)y) return -1;
else return 0;
}
int ConparFuncFloat(const void *x, const void *y){
if(* (float *)x > *(float *)y) return 1;
else if(* (float *)x < *(float *)y) return -1;
else return 0;
}
int ComparFuncStructName(const void *x, const void *y){
const char *pa = *(const char**)x;
const char *pb = *(const char**)y;
return strcmp(pa,pb);
}
int ComparFuncStructPrice(const void *x, const void *y){
if(* (float *)x > *(float *)y) return 1;
else if(* (float *)x < *(float *)y) return -1;
else return 0;
}
我想这样做,当用户选择 3 时,它会按价格对产品下的 PRICES 数组进行排序,如果用户选择 4,它应该按名称排序,在这两种情况下它都应该输出价格和名称,只是排序的差异。
在比较函数中,指针(x
和 y
在你的例子中)是指向数组元素的指针。如果数组是 int
,那么它是指向 int
的指针(即 int *
)。如果它是一个结构数组,那么它们是指向 结构 的指针(例如 product *
)。
要访问结构的成员,您当然需要使用正确的结构指针访问,例如箭头运算符 ->
.
如果将指针保存在适当的变量中也会更容易,这样您就不必一直进行所有转换。事实上,如果您想将传递的数据用作指针而不是值,则根本不需要强制转换,因为 void *
可以隐式转换为几乎任何其他指针类型(函数指针除外)。
所以对于你的结构比较功能,你可以做例如
int ComparFuncStructName(const void *x, const void *y){
const product *a = x;
const product *b = y;
return strcmp(a->name, b->name);
}
或者当然,由于您正在对结构数组进行排序,数组的元素大小就是结构的大小,因此您也需要修复它:
qsort(prices, charCount, sizeof prices[0], ComparFuncStructName);
哦,你对结构中元素数量的计算也是错误的。公式为sizeof array / sizeof array[0]
。 总是。无论数组的类型或其元素如何。 sizeof
的结果是 always size_t
,因此您也应该将它用作所有 sizeof
操作的类型。
所以你需要做
size_t charCount = sizeof prices / sizeof prices[0];
关于一个不相关且更具风格的注释:不要将 printf
调用与 for
循环的增量表达式结合使用。这将使代码更难阅读、理解、遵循和(最重要的)维护。
改为将所有语句放在循环体中:
for (int l = 0; l < charCount; l++)
printf("%s", prices[l].name);
您也不需要为循环使用不同的迭代变量。它们对于自己范围内的循环是本地的,因此您可以对所有循环重复使用 i
。
改变这个:
qsort(prices, (size_t)doubleCount, sizeof(double), ComparFuncStructPrice);
至:
qsort(prices, 6, sizeof(prices[0]), ComparFuncStructPrice);
因为结构数组只有一个大小,无论您是想按名称还是按价格排序。此外,无论您想按名称还是按价格排序,数组中每个元素的大小都等于结构的大小。
类似于按名称排序。
另外,你的比较函数是错误的。首先,您需要将每个 void 指针转换为一个结构。那么,就需要使用struct的相关字段进行比较了。
对于价格比较,使用 less 和 more 运算符。如果简单地减去,会得到错误的结果。
将所有内容放在一起(并丢弃非结构数组),您将得到:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 20
typedef struct product
{
double price;
char name[LEN];
} product;
int ComparFuncStructName(const void *x, const void *y);
int ComparFuncStructPrice(const void *x, const void *y);
/*
void PrintStructArray(product *items, int len);
*/
int main(void)
{
unsigned option;
product prices[] = {{0.75f, "Milk"}, {0.99f, "Yogurt"}, {3.19f, "Cucumber"},
{1.09f, "Orange"}, {0.80f, "Bread"}, {0.99f, "Juice"}};
size_t pricesCount = sizeof prices / sizeof prices[0];
while (1)
{
printf("\n\nSelect your action!\n\n");
printf("3. Sort structures by price\n");
printf("4. Sort structures by name\n");
printf("0. Exit\n");
scanf("%u", &option);
switch (option)
{
case 3:
qsort(prices, pricesCount, sizeof(prices[0]), ComparFuncStructPrice);
for (size_t k = 0; k < pricesCount; printf("%f ", prices[k].price), k++);
break;
case 4:
qsort(prices, pricesCount, sizeof(prices[0]), ComparFuncStructName);
for (size_t l = 0; l < pricesCount; printf("%s ", prices[l].name), l++);
break;
case 0:
exit(1);
break;
default:
printf("Only selections from 1 to 4 and 0 are accepted\n");
}
}
return EXIT_SUCCESS;
}
int ComparFuncStructName(const void *x, const void *y){
const product* pa = (const product*) x;
const product* pb = (const product*) y;
return strcmp(pa->name, pb->name);
}
int ComparFuncStructPrice(const void *x, const void *y){
const product* pa = (const product*) x;
const product* pb = (const product*) y;
return (pa->price > pb->price) - (pa->price < pb->price);
}
输出(如果我选择按名称排序):
Select your action!
3. Sort structures by price
4. Sort structures by name
0. Exit
Bread Cucumber Juice Milk Orange Yogurt
Select your action!
3. Sort structures by price
4. Sort structures by name
0. Exit