使用 qsort
标准库排序函数
使用 qsort 是 CoddyKit 上的免费 C Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。
标准库排序
C 的标准库在 <stdlib.h> 中提供了 qsort。只要提供一个比较函数,它就可以对任意数组排序,因此您很少需要自己编写排序算法。
qsort 的签名
函数原型为:
base指向第一个元素的指针nmemb元素数量size每个元素占用的字节数compar比较函数指针
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));
编写比较器
比较器会接收两个 const void *。请将它们转换为实际类型,进行解引用,然后返回负数、零或正数。
#include <stdio.h>
#include <stdlib.h>
int cmp_int(const void *a, const void *b) {
int x = *(const int *)a;
int y = *(const int *)b;
return (x > y) - (x < y); /* safe, no overflow */
}
int main(void) {
int a[] = {5, 2, 9, 1, 3};
qsort(a, 5, sizeof(int), cmp_int);
for (int i = 0; i < 5; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}避免在比较器中使用减法
返回 x - y 时,大整数可能发生溢出,从而产生错误结果。请改用布尔值相减的惯用写法 (x > y) - (x < y)。
#include <stdio.h>
int main(void) {
int x = 2000000000, y = -2000000000;
printf("unsafe x-y = %d\n", x - y); /* overflow */
printf("safe = %d\n", (x > y) - (x < y));
return 0;
}降序排列
要按降序排序,只需反转比较结果。
#include <stdio.h>
#include <stdlib.h>
int cmp_desc(const void *a, const void *b) {
int x = *(const int *)a, y = *(const int *)b;
return (y > x) - (y < x);
}
int main(void) {
int a[] = {5, 2, 9, 1, 3};
qsort(a, 5, sizeof(int), cmp_desc);
for (int i = 0; i < 5; i++) printf("%d ", a[i]);
printf("\n");
return 0;
}对字符串排序
要对 char * 数组排序,比较器接收的是指向这些指针的指针。请将其转换为 const char * const *,然后调用 strcmp。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int cmp_str(const void *a, const void *b) {
const char *x = *(const char * const *)a;
const char *y = *(const char * const *)b;
return strcmp(x, y);
}
int main(void) {
const char *names[] = {"charlie", "alice", "bob"};
qsort(names, 3, sizeof(char *), cmp_str);
for (int i = 0; i < 3; i++) printf("%s ", names[i]);
printf("\n");
return 0;
}对结构体排序
您可以根据任意字段对结构体数组排序。这里我们按年龄排列人员。
#include <stdio.h>
#include <stdlib.h>
typedef struct { char name[16]; int age; } Person;
int by_age(const void *a, const void *b) {
const Person *p = a, *q = b;
return (p->age > q->age) - (p->age < q->age);
}
int main(void) {
Person ppl[] = {{"Ann", 30}, {"Ben", 25}, {"Cid", 40}};
qsort(ppl, 3, sizeof(Person), by_age);
for (int i = 0; i < 3; i++) printf("%s %d\n", ppl[i].name, ppl[i].age);
return 0;
}多关键字排序
要打破平局,请在第一个字段相等时比较第二个字段。这样会先按年龄排序,再按姓名的字母顺序排序。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct { char name[16]; int age; } Person;
int cmp(const void *a, const void *b) {
const Person *p = a, *q = b;
if (p->age != q->age)
return (p->age > q->age) - (p->age < q->age);
return strcmp(p->name, q->name);
}
int main(void) {
Person ppl[] = {{"Zoe", 30}, {"Amy", 30}, {"Bo", 25}};
qsort(ppl, 3, sizeof(Person), cmp);
for (int i = 0; i < 3; i++) printf("%d %s\n", ppl[i].age, ppl[i].name);
return 0;
}qsort 不稳定
C 标准不要求 qsort 具备稳定性。如果需要稳定排序,请在比较器中加入一个用于打破平局的键,例如原始索引。
bsearch 的配套使用
bsearch 使用相同风格的比较器,在已排序的数组上执行二分查找。将它与 qsort 配合使用,可以快速查找。
#include <stdio.h>
#include <stdlib.h>
int cmp_int(const void *a, const void *b) {
int x = *(const int *)a, y = *(const int *)b;
return (x > y) - (x < y);
}
int main(void) {
int a[] = {1, 3, 5, 7, 9};
int key = 7;
int *found = bsearch(&key, a, 5, sizeof(int), cmp_int);
printf("%s\n", found ? "found" : "missing");
return 0;
}为什么使用 qsort
标准的 qsort 经过充分测试,通常是经过调优的内省排序混合算法,并且适用于任何类型。只有在需要稳定性,或需要库无法提供的特殊行为时,才应考虑自己编写排序算法。
快速检查
测试您对 qsort 的理解。
回顾
您已经学习了如何使用标准库排序函数。
qsort(base, nmemb, size, compar)可以对任意数组排序- 比较器将
const void *转换为实际类型,并返回比较结果的符号 - 避免使用减法;改用
(x > y) - (x < y) qsort不保证稳定;bsearch是它配套的查找函数
常见问题解答
「使用 qsort」课时是免费的吗?
是的 — 「使用 qsort」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。
「使用 qsort」这节课中我会学到什么?
标准库排序函数 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「使用 qsort」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C Academy 课中编写并运行代码吗?
能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。