0Pricing
C Academy · 课时

使用 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 反馈 — 无需本地设置。

此课程中的所有课时

  1. 冒泡排序与插入排序
  2. 快速排序
  3. 归并排序
  4. 使用 qsort
← 返回 C Academy