c语言qsort函数具体怎么用?

99ANYc3cd6
预计阅读时长 20 分钟
位置: 首页 C语言 正文

qsort 是 C 标准库 <stdlib.h> 中提供的一个强大且高效的快速排序函数,它的优点是通用性强,可以用来排序任何类型的数据(如整数、浮点数、结构体等),只要你能告诉它如何比较两个元素。

c语言qsort函数怎么用
(图片来源网络,侵删)

核心要点

使用 qsort 最关键的一点是:你必须自己编写一个“比较函数”,这个函数告诉 qsort 如何判断两个元素的先后顺序。


函数原型

我们来看一下 qsort<stdlib.h> 中的原型:

void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));

这个函数看起来有点复杂,我们来逐个解析它的参数:

参数 类型 含义
base void * 待排序数组的起始地址void* 是一个通用指针,可以指向任何类型的数据。
nmemb size_t 数组中元素的数量
size size_t 数组中单个元素的大小(以字节为单位),这个参数非常重要,因为它让 qsort 能够正确地在内存中移动元素。
compar int (*)(const void *, const void *) 指向比较函数的指针,这是 qsort 的核心,你需要自己实现这个函数来定义排序规则。

比较函数

这是整个 qsort 用法的核心和难点,比较函数的原型是固定的:

c语言qsort函数怎么用
(图片来源网络,侵删)
int compar(const void *a, const void *b);

工作原理: qsort 会反复调用你的 compar 函数,每次传入数组中的两个元素的地址(ab),你的函数需要根据这两个元素的关系,返回一个整数值:

返回值 含义
负数 (< 0) a 应该排在 b 前面
(= 0) ab 相等,它们的相对位置无所谓。
正数 (> 0) a 应该排在 b 后面

类型转换: 由于 compar 函数的参数是 const void *,你不能直接对它们进行解引用(如 *a),你必须先将它们强制转换回你数组元素的原始指针类型,然后再解引用。


完整使用步骤

  1. 包含头文件#include <stdlib.h>
  2. 定义比较函数:根据你的数据类型,编写一个符合上述规则的 compar 函数。
  3. 准备数据:将待排序的数据放入一个数组中。
  4. 调用 qsort:传入数组的首地址、元素个数、单个元素大小和你的比较函数。

实例讲解

我们通过几个经典的例子来掌握 qsort 的用法。

示例1:对整数数组进行升序排序

这是最简单的例子。

c语言qsort函数怎么用
(图片来源网络,侵删)
#include <stdio.h>
#include <stdlib.h> // 必须包含此头文件
// 1. 定义比较函数
// 参数 a 和 b 是数组中两个元素的地址 (void* 类型)
int compare_ints(const void *a, const void *b) {
    // 将 void* 指针强制转换为 int* 指针,然后解引用获取值
    int arg1 = *(const int*)a;
    int arg2 = *(const int*)b;
    // 实现升序排序
    if (arg1 < arg2) return -1; // a < b, a 排在 b 前面
    if (arg1 > arg2) return 1;  // a > b, a 排在 b 后面
    return 0;                   // a == b
}
int main() {
    int arr[] = {10, 5, 8, 20, 3, 15};
    int n = sizeof(arr) / sizeof(arr[0]);
    printf("排序前: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    // 2. 调用 qsort
    // base: arr (数组首地址)
    // nmemb: n (元素个数)
    // size: sizeof(int) (单个元素大小)
    // compar: compare_ints (我们的比较函数)
    qsort(arr, n, sizeof(int), compare_ints);
    printf("排序后: ");
    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");
    return 0;
}

输出:

排序前: 10 5 8 20 3 15 
排序后: 3 5 8 10 15 20 

代码解析:

  • compare_ints 函数接收两个 const void*,将它们转成 const int*,再解引用得到 int 值。
  • 通过比较这两个 int 值,返回 -1, 0, 或 1,实现了升序排序。

示例2:对浮点数数组进行降序排序

这个例子展示了如何改变排序规则(从升序变为降序)。

#include <stdio.h>
#include <stdlib.h>
// 比较函数,用于降序排序
int compare_floats_desc(const void *a, const void *b) {
    float arg1 = *(const float*)a;
    float arg2 = *(const float*)b;
    // 实现降序排序
    if (arg1 > arg2) return -1; // a > b, a 排在 b 前面
    if (arg1 < arg2) return 1;  // a < b, a 排在 b 后面
    return 0;
}
int main() {
    float arr[] = {3.14, 1.5, 9.8, 2.2, 5.0};
    int n = sizeof(arr) / sizeof(arr[0]);
    printf("排序前: ");
    for (int i = 0; i < n; i++) {
        printf("%.2f ", arr[i]);
    }
    printf("\n");
    qsort(arr, n, sizeof(float), compare_floats_desc);
    printf("排序后: ");
    for (int i = 0; i < n; i++) {
        printf("%.2f ", arr[i]);
    }
    printf("\n");
    return 0;
}

输出:

排序前: 3.14 1.50 9.80 2.20 5.00 
排序后: 9.80 5.00 3.14 2.20 1.50 

示例3:对结构体数组进行排序(按年龄)

qsort 的真正威力在于排序复杂数据类型,比如结构体。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// 定义一个学生结构体
typedef struct {
    char name[50];
    int age;
    float score;
} Student;
// 比较函数:按年龄升序排序
int compare_by_age(const void *a, const void *b) {
    // 将 void* 转换为 Student*,再解引用获取结构体
    Student *studentA = (Student*)a;
    Student *studentB = (Student*)b;
    // 比较年龄
    return (studentA->age - studentB->age);
}
int main() {
    Student students[] = {
        {"Alice", 20, 88.5},
        {"Bob", 19, 92.0},
        {"Charlie", 21, 85.5},
        {"David", 19, 95.0}
    };
    int n = sizeof(students) / sizeof(students[0]);
    printf("按年龄排序前:\n");
    for (int i = 0; i < n; i++) {
        printf("%s, %d, %.1f\n", students[i].name, students[i].age, students[i].score);
    }
    qsort(students, n, sizeof(Student), compare_by_age);
    printf("\n按年龄排序后:\n");
    for (int i = 0; i < n; i++) {
        printf("%s, %d, %.1f\n", students[i].name, students[i].age, students[i].score);
    }
    return 0;
}

输出:

按年龄排序前:
Alice, 20, 88.5
Bob, 19, 92.0
Charlie, 21, 85.5
David, 19, 95.0
按年龄排序后:
Bob, 19, 92.0
David, 19, 95.0
Alice, 20, 88.5
Charlie, 21, 85.5

注意: return (studentA->age - studentB->age); 是一种简洁的写法,它利用了整数相减会得到负数、零或正数的特性,完美符合 compar 函数的要求。


常见陷阱与注意事项

  1. 忘记包含 <stdlib.h>:这是最常见的新手错误。
  2. 比较函数逻辑错误:特别是升序和降序的逻辑容易写反。升序时,小的在前,返回负数降序时,大的在前,返回负数
  3. 指针类型转换错误:确保将 void* 转换成你数组元素的正确指针类型(如 int*, Student*)。
  4. size 参数错误size 应该是 sizeof(你的元素类型)sizeof(int),如果传错,qsort 在内存中移动元素时会发生错位,导致程序崩溃或错误结果。
  5. nmemb 参数错误:确保元素个数计算正确,通常是 sizeof(数组) / sizeof(数组[0])

qsort 是 C 语言中一个功能强大且必须掌握的排序工具,它的核心在于自定义比较函数,只要你能清晰地定义出两个元素之间的“大小”关系,你就可以使用 qsort 对任何数据类型进行高效的排序,记住它的四个参数,特别是 sizecompar,就能灵活运用它了。

-- 展开阅读全文 --
头像
刚安装好织梦 打不开
« 上一篇 03-06
织梦前台为何不显示子栏目?
下一篇 » 03-06

相关文章

取消
微信二维码
支付宝二维码

目录[+]