C语言如何实现可按结构体不同类型成员排序的通用函数?
方案说明
不需要编写多份重复的排序/搜索逻辑,利用C标准库的通用排序/搜索函数 + 字段对应的比较函数即可实现,90%的公共逻辑完全复用。
核心实现思路
- C标准库的
qsort()、bsearch()本身就是泛型实现,不绑定具体数据类型,只需要传入对应数据的比较函数即可 - 你只需要为3个字段分别写3个极短的比较函数,排序、搜索的核心逻辑完全复用标准库实现,没有重复代码
具体代码实现
1. 基础定义
#include <stdio.h> #include <stdlib.h> #include <string.h> #define NAME_SIZE 32 struct Substance { char name[NAME_SIZE]; int mass; double halftime; };
2. 字段对应比较函数(仅3个短函数,无重复逻辑)
// 按name比较 int cmp_substance_name(const void* a, const void* b) { const struct Substance* sa = (const struct Substance*)a; const struct Substance* sb = (const struct Substance*)b; return strcmp(sa->name, sb->name); } // 按mass比较 int cmp_substance_mass(const void* a, const void* b) { const struct Substance* sa = (const struct Substance*)a; const struct Substance* sb = (const struct Substance*)b; return sa->mass - sb->mass; } // 按halftime比较 int cmp_substance_halftime(const void* a, const void* b) { const struct Substance* sa = (const struct Substance*)a; const struct Substance* sb = (const struct Substance*)b; if (sa->halftime < sb->halftime) return -1; if (sa->halftime > sb->halftime) return 1; return 0; }
3. 调用逻辑
int main() { // 示例数据 struct Substance substances[] = { {"Uranium", 238, 4.468e9}, {"Radon", 220, 55.6}, {"Zirconium", 91, 1.53e19}, {"Radon", 222, 3.8235} }; int len = sizeof(substances) / sizeof(substances[0]); int choice; printf("Do you want to sort by (1) name, (2) mass or (3) halftime: "); scanf("%d", &choice); // 根据选择传入对应的比较函数即可,排序逻辑完全复用qsort switch(choice) { case 1: qsort(substances, len, sizeof(struct Substance), cmp_substance_name); break; case 2: qsort(substances, len, sizeof(struct Substance), cmp_substance_mass); break; case 3: qsort(substances, len, sizeof(struct Substance), cmp_substance_halftime); break; default: printf("无效选择\n"); return 1; } // 打印结果逻辑完全通用,不需要修改 printf("\nSorted list:\n%-12s %-8s %s\n", "Name", "Mass", "Halftime"); for (int i = 0; i < len; i++) { printf("%-12s %-8d %.4g\n", substances[i].name, substances[i].mass, substances[i].halftime); } return 0; }
搜索场景的复用
如果要做搜索,直接用标准库的bsearch(),传入和排序时相同的比较函数即可,不需要额外写搜索逻辑:
// 示例:按mass搜索值为222的元素 struct Substance key = {.mass = 222}; struct Substance* res = bsearch(&key, substances, len, sizeof(struct Substance), cmp_substance_mass); if (res) { printf("找到元素:%s\n", res->name); }
不建议之前转换方案的原因
- 转字符串存储/比较会额外占用内存、增加CPU开销,还会出现数字转字符串后排序顺序和数值顺序不一致的问题(比如"100"按字符串排序会小于"2")
- 全部存同一种类型会丢失精度,比如double转字符串会有截断问题,int转double虽然精度损失小,但字符串排序的问题仍然存在
内容的提问来源于stack exchange,提问作者Silop
相关产品推荐
相关产品推荐

