CPrimer Plus第十六章C预处理器和C库总结2-qsort函数

一.qsort函数

1.功能:​​ 对任意类型的数组进行排序

cs 复制代码
void qsort(void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *));

void *base:指向要排序的数组的​​起始地址​ ​(第一个元素的地址)

类型是 void *(通用指针),这意味着 qsort可以处理任何数据类型的数组

size_t nmemb:数组中元素的​​数量

size_t size: 数组中​​每个元素的大小​ ​(以字节为单位)

使用 sizeof(数组元素类型)或 sizeof(array[0])来获取

int (*compar)(const void *, const void *)这是一个​​函数指针​ ​,指向用户提供的​​比较函数

这个函数决定了排序的顺序(升序、降序、按特定规则)

它接受两个 const void *参数(指向要比较的两个元素的指针)

它返回一个 int值,表示两个元素的比较结果

2.核心:比较函数 compar

​​函数签名必须匹配

cs 复制代码
int your_comparison_function_name(const void *a, const void *b);

参数 a和 b是指向数组中两个待比较元素的指针

使用 const void *是为了保证函数不会修改原始数据,并且 qsort可以传递任何类型的指针

返回值必须是 int

返回值规则:
如果 a指向的元素 ​应该排在​ b指向的元素 ​前面​ ,则返回一个 ​负数​ (通常用 -1表示)
如果 a指向的元素 ​等于​ b指向的元素,则返回 ​0​
如果 a指向的元素 ​应该排在​ b指向的元素 ​后面​ ,则返回一个 ​正数​ (通常用 1表示)
简单记忆:​ a - b返回负、零、正,对应 a排在 b前、相等、后

3.示例 1:对 int数组升序排序

cs 复制代码
int compare_ints_asc(const void *a, const void *b) {
    // 1. 将 void* 转换为 int*
    const int *ia = (const int *)a;
    const int *ib = (const int *)b;

    // 2. 比较值并返回结果
    // 升序:a - b
    return (*ia - *ib);
    // 更严谨的写法(避免整数溢出):
    // if (*ia < *ib) return -1;
    // else if (*ia > *ib) return 1;
    // else return 0;
}

解释:​ ​ *ia - *ib如果 ia的值小,结果是负数,表示 ia应该排在 ib前面(升序)。如果 ia的值大,结果是正数,表示 ia应该排在 ib后面(升序)。相等则返回 0
注意:​ ​ 直接使用 *ia - *ib在值非常大时可能导致整数溢出(例如 INT_MIN - 1)。更安全的方式是使用 if语句进行显式比较

4.示例 2:对 int数组降序排序

cs 复制代码
int compare_ints_desc(const void *a, const void *b) {
    const int *ia = (const int *)a;
    const int *ib = (const int *)b;
    // 降序:b - a
    return (*ib - *ia);
    // 安全写法:
    // if (*ib < *ia) return -1; // b < a, 我们希望 b 排前面?不,降序需要 b > a 才排前面
    // else if (*ib > *ia) return 1; // b > a, 我们希望 b 排后面?不
    // else return 0;
    // 更清晰的降序写法:
    if (*ia > *ib) return -1; // a > b, 我们希望 a 排前面 -> 返回负
    else if (*ia < *ib) return 1; // a < b, 我们希望 a 排后面 -> 返回正
    else return 0;
}

解释:​ ​ 要降序,只需反转比较结果。*ib - *ia如果 ib的值小(即 ia的值大),结果是负数,表示 ia应该排在 ib前面(符合降序:大数在前)。如果 ib的值大(即 ia的值小),结果是正数,表示 ia应该排在 ib后面(符合降序:小数在后)。同样可以使用 if语句显式控制

5.示例 3:对 char *数组(字符串数组)按字典序升序排序

cs 复制代码
#include <string.h> // 需要 strcmp

int compare_strings_asc(const void *a, const void *b) {
    // 1. 将 void* 转换为 char** (因为数组元素是 char*, 所以指针是指向 char* 的指针)
    const char **str_a = (const char **)a;
    const char **str_b = (const char **)b;

    // 2. 使用 strcmp 比较字符串
    return strcmp(*str_a, *str_b);
}
cs 复制代码
return strcmp(*(const char **)a, *(const char **)b);
复制代码
6.对结构体数组按特定字段排序
cs 复制代码
struct Person {
    char name[50];
    int age;
    float height;
};
复制代码
        按 age升序排序:
cs 复制代码
int compare_person_by_age_asc(const void *a, const void *b) {
    const struct Person *pa = (const struct Person *)a;
    const struct Person *pb = (const struct Person *)b;

    // 比较 age 字段
    if (pa->age < pb->age) return -1;
    else if (pa->age > pb->age) return 1;
    else return 0;
    // 或者更简洁(注意可能的溢出):
    // return (pa->age - pb->age);
}
复制代码
        按 name字段字典序升序排序
cs 复制代码
int compare_person_by_name_asc(const void *a, const void *b) {
    const struct Person *pa = (const struct Person *)a;
    const struct Person *pb = (const struct Person *)b;

    // 直接比较结构体内的 name 字符数组
    return strcmp(pa->name, pb->name);
}
复制代码
按 height降序排序,若 height相同则按 age升序排序:
     
cs 复制代码
int compare_person_by_height_desc_age_asc(const void *a, const void *b) {
    const struct Person *pa = (const struct Person *)a;
    const struct Person *pb = (const struct Person *)b;

    // 先比较 height (降序)
    if (pa->height > pb->height) return -1; // pa 更高,我们希望 pa 排前面 -> 返回负
    else if (pa->height < pb->height) return 1; // pa 更矮,我们希望 pa 排后面 -> 返回正
    else {
        // height 相等,再按 age 升序
        return (pa->age - pb->age); // 升序直接减
    }
}
复制代码
   
7.​​原地排序:​​ qsort直接修改传入的数组 (base),是​​原地排序​​算法。原始数组的顺序会被改变。
相关推荐
资深技术分享员11 小时前
Geejing WebBuilder 日志、在线用户、系统监控,出问题时的三个第一现场
java·运维·数据库
卓怡学长11 小时前
w202springboot基于B_S架构的图书信息管理系统
java·spring boot·spring·intellij-idea
走到天涯海角11 小时前
用springBoot写几个简单的接口
java·spring boot·intellij-idea
troy12811 小时前
Java 技术栈全景指南:从基础到微服务的完整知识体系
java·开发语言·微服务
Escalating_xu11 小时前
【C 语言】深入理解指针(2):数组名、数组传参、二级指针与指针数组
java·c语言·开发语言
景熙552311 小时前
JDBC 详解:从原理到实战(含完整可运行 Demo)
java·spring·tomcat·mybatis·jdbc
Allen_LVyingbo12 小时前
信息化部门在AI时代的编程转移路径分析(上)
人工智能·python·算法·健康医疗·数据库开发·时序数据库·数据库架构
程序猿乐锅12 小时前
一文讲透缓存穿透、击穿和雪崩
java·redis·spring·缓存·mybatis
七牛云行业应用12 小时前
Jev 报 401 / api_key_required 怎么解决:TypeSafe AI 官方错误码表与排查步骤
算法·github
xcl092512 小时前
西安同城货运系统源码开发实战 核心功能实现与部署全指南
java·spring boot