深入解析C语言qsort排序原理

使用冒泡排序模仿qsort实现通用算法(c语言) 提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、理解qsort函数1.什么是qsort函数2.qsort函数对数组排列二、使用步骤1.引入库2.读入数据总结 前言 提示:这里可以添加本文要记录的大概内容: qsort函数,是C语言中自带函数库中就有快速排序——qsort函数,本篇文章用冒泡排序模拟实现qsort的功能,实现对数组、字符串、结构体等结构进行升序或降序排序。 提示:以下是本篇文章正文内容,下面案例可供参考 一、理解qsort函数 1.什么是qsort函. 阅读详情

深入解析C语言qsort排序原理

大家好,这篇文章将带你深度理解 C 语言 qsort 排序的底层原理,从内存布局、比较函数调用,到元素交换和排序算法逻辑,逐步解析,让初学者也能看懂。

如果你觉得文章对你有帮助,欢迎 点赞支持 ,我会持续更新更多 算法与数据结构相关内容。

同时,如果你喜欢我的内容,可以 关注我/订阅专栏,不错过后续更多实用教程和深度解析。
qsort 是 C 标准库 <stdlib.h> 提供的通用排序函数,它可以对任意类型的数组进行排序。

函数原型:

void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*));
参数含义
base指向数组首元素的指针,类型是 void*,所以可以是任意类型数组
nitems数组中元素的数量
size每个元素的字节大小(sizeof(元素类型))
compar比较函数指针,接受两个 const void* 参数,返回值为整数,规定如下:<0 表示第一个元素小于第二个0 表示相等>0 表示第一个元素大于第二个

compar 模板

整数升序排序

int cmp_int(const void *a, const void *b) {
    // 先转换类型
    int x = *(int*)a;
    int y = *(int*)b;
    
    // if (x < y) {
    //     return -1;
    // }
    // else if (x > y) {
    //     return 1;
    // }
    // 
    // return 0;
    
    return x - y; // 升序排序
    
    // 如果要降序呢?调换一下位置即可
    // return y - x;
    
}

通过解析 cmp_int 理解 compar

我们要做的是:用 qsort 排序整数数组。

函数原型:

int cmp_int(const void *a, const void *b)

Ⅰ为什么参数是 const void*

  1. qsort 是一个 通用排序函数,可以排序任何类型的数组:整数、浮点数、结构体等等。
  2. void* 表示 指向任意类型的指针。
  3. const 表示 函数不会修改数组里的值,只是比较它们大小。

也就是说,a 和 b 是 指向数组元素的地址,但函数不会改变它们的内容。

Ⅱ先把指针变成我们能用的整数

int x = *(int*)a;
int y = *(int*)b;

逐步解释:

  1. (int*)a → 把 void* 转成 int*,告诉编译器这是一个整数地址
  2. *(int*)a → 取出这个地址上的整数,也就是数组里的真实数字
  3. 同理,y = *(int*)b; 也取出第二个数字

Ⅲ比较两数

方式一:原型形式

if (x < y) return -1;  // x 小于 y → 排在前面
else if (x > y) return 1; // x 大于 y → 排在后面
else return 0;           // x 等于 y → 不动

解释:

  • qsort 通过返回值判断两个元素的顺序
  • <0 → a 在前
  • 0 → 不变
  • >0 → b 在前

方式二:简化写法(可能溢出)

return x - y;
  • 直接用整数相减得到结果
  • 简洁,但如果数字很大或很小,可能溢出(计算结果超出整数范围),排序就错了

方式三:优化(推荐)

return (x > y) - (x < y);
  • (x > y) → 如果 x > y 返回 1,否则 0
  • (x < y) → 如果 x < y 返回 1,否则 0
  • 减法得到 -1、0、1 → 完美对应 qsort 规则
  • 没有溢出风险,代码既优雅又安全

Ⅳ示例

#include <stdio.h>
#include <stdlib.h>

int cmp_int(const void *a, const void *b) {
    int x = *(int*)a;
    int y = *(int*)b;
    return (x > y) - (x < y); 
}

int main() {
    int arr[] = {5, 2, 9, 1};
    int n = sizeof(arr)/sizeof(arr[0]);

    qsort(arr, n, sizeof(int), cmp_int);

    for (int i = 0; i < n; i++)
        printf("%d ", arr[i]);
    return 0;
}

输出:

1 2 5 9

浮点数降序排序

int cmp_double_desc(const void *a, const void *b) {
    // 先转换类型
    double x = *(double*)a;
    double y = *(double*)b;
    
    return (y > x) - (y < x); // 返回正数/负数/0
}

提问:浮点数排序可以使用 return x - y 吗?

答案是不可以

int cmp_float(const void *a, const void *b) {
    double x = *(const double*)a;
    double y = *(const double*)b;
    return x - y;  // 错误
}

原因

  1. 返回值类型错误
    • qsort 比较函数必须返回 int
    • x - y 是 double,会被强制转换为 int
    • 小差值(如 0.0001)转换成 int 会变成 0 → 排序错误
  2. 浮点精度问题
    • 浮点数很接近,减法可能丢失精度
    • 导致相近的两个元素被认为相等 → 排序结果不正确

字符串数组排序

int cmp_str(const void *a, const void *b) {
    // 先转换类型
    const char *str1 = *(const char **)a;
    const char *str2 = *(const char **)b;

    return strcmp(str1, str2);
}

结构体排序

typedef struct {
    int a;
    int b;
} Item;

int cmp_a_b(const void *x, const void *y) {
    // 先转换类型
    const Item *i1 = (const Item*)x;
    const Item *i2 = (const Item*)y;
    
    // 常用
    if (i1->a != i2->a)
        return i1->a - i2->a;   // a 升序
    
    return i1->b - i2->b;       // a 相同则 b 升序
    
    // 防溢出优化
    // if (i1->a != i2->a)
    //     return (i1->a > i2->a) - (i1->a < i2->a);  // a 升序
	//
    // return (i1->b > i2->b) - (i1->b < i2->b);	   // a 相同则 b 升序
}

内部排序原理

假设我们要排序一个结构体数组:

typedef struct {
    int a;
    int b;
} Item;

调用方式:

qsort(arr, n, sizeof(Item), cmp_a_b);

内部算法选择

C 标准库 qsort 的具体实现因平台而异,但通常采用 混合排序算法:

  1. 快速排序 (Quicksort)
    • 平均时间复杂度 O(n log n)
    • 通过基准分区,把小的放左,大的放右
    • 对递归深度过大或接近有序数组可能退化
  2. Introsort / 混合排序
    • 先用快速排序
    • 当递归深度过深 → 切换为堆排序,保证最坏 O(n log n)
    • 小数组使用插入排序,减少递归开销

比较函数调用机制

  • qsort 通过传入指针调用比较函数:
cmp_a_b(&arr[i], &arr[j]);
  • 内部操作步骤:
  1. void* 转 Item*
  2. 取出需要比较的字段(例如 a, b)
  3. 返回 -1/0/1 表示排序顺序

注意:比较函数只读指针,不修改数组,只提供顺序信息。

元素交换机制

  • 当比较结果显示顺序需要调整时,qsort 交换元素:
swap(void *p1, void *p2, size_t size) {
    char tmp[size];
    memcpy(tmp, p1, size); // 临时保存 p1
    memcpy(p1, p2, size);  // p1 = p2
    memcpy(p2, tmp, size); // p2 = p1
}
  • 对结构体数组:
    • 每次交换整个结构体内存块(包括所有字段)

排序流程(以快速排序为例)

  1. 选择基准元素 (pivot)
    • 例如选择第一个或中间元素
  2. 分区
    • 遍历数组,把小于 pivot 的元素放左边,大于 pivot 的放右边
  3. 递归
    • 分别对左半部分和右半部分递归排序
  4. 优化
    • 小数组 → 插入排序
    • 递归过深 → 堆排序
VisionPro脚本实战:用C#替代QuickBuild,让复杂定位项目代码更清爽 本文探讨了如何通过C#脚本重构VisionPro复杂定位项目,替代臃肿的QuickBuild架构。通过实战案例展示了脚本化开发如何减少60%代码量并提升35%运行效率,使项目更易维护。文章详细介绍了环境搭建、多模板定位重构及高级技巧,帮助开发者突破QuickBuild限制,实现更高效的视觉应用开发。 阅读详情

相关推荐

Hive中的四种排序方式(order by,sort by,distribute by,cluster by)使用与区别详解

在平时的Hive数仓开发工作中经常会用到排序,而Hive中支持的排序方式有四种,这里结合具体的案例详细介绍一下他们的使用与区别: order by sort by distribute by cluster by 一、order by(全局排序) 1、作用:全局排序,只有一个reducer。 order by 会对输入做全局排序,因此只有一个reducer(多个reducer无法保证全局有序),也正因为只有一个reducer,所以当输入的数据规模较大时会导致计算时间较长。   set hive.mapr

weixin_43230682的博客 1万+

C语言---qsort 函数详解与实现(快速排序任何类型)

我们以前学习过一些排序算法,如冒泡,选择,归并,快速排序等等,它们排序的速度有快有慢,但这些排序都只能排序一种类型的数据,如果想再排序另外一种类型得数据就需要再另写一个排序,所以有没有什么排序是万能的,既能排整形,又能排浮点型,还能排字符串类型等等的排序呢?答案是有的,它就是 qsort 函数。qsort 函数官方定义:大家也都能了解,这个函数的重点就在于 compar 这一函数指针。

2302_78684687的博客 4998

从ET到PT阶段:一文详解汽车零部件DV与PV测试的完整流程(含常见问题解析)

本文深入解析汽车零部件开发中的DV(设计验证)与PV(性能验证)测试全流程,涵盖从ET到PT阶段的关键技术要点与常见问题解决方案。针对车载开发工程师,提供实战指南与优化策略,帮助提升零部件质量与生产效率,确保符合行业标准与市场需求。

weixin_29273849的博客 782

对于c语言中冒泡排序以及qsort函数的解析

本文深入解析了C语言中的冒泡排序和qsort函数。首先介绍了冒泡排序的基本原理、优化方法及使用异或交换的技巧,然后详细剖析qsort函数的四个参数及其通用排序机制。文章通过代码示例展示了如何模拟实现qsort函数,强调其核心在于比较函数和内存交换机制。最后提供了几道练习题,帮助读者实践应用这些排序方法。全文不仅讲解技术细节,更鼓励读者培养编程思维和解决问题的能力,将算法学习中锻炼的耐心和逻辑思维应用于生活挑战。

2503_92929084的博客 1271

Keil MDK v6迁移指南:从AC5到AC6的编译器升级与工程适配

编译器是嵌入式开发的底层基石,决定了代码的执行效率与工程的可维护性。随着ARM工具链向LLVM/Clang架构演进,Arm Compiler 6(AC6)正逐步取代经典的AC5,成为Keil MDK的核心编译引擎。AC6在C11标准支持、代码优化、诊断信息及LTO链接优化上全面超越AC5,但迁移过程中往往伴随内联汇编重写、类型检查严格化、库兼容性等问题。理解编译器差异、掌握CMSIS-Toolbox的工程描述机制,能帮助嵌入式工程师在Cortex-M系列项目中平滑过渡。本文结合Cortex-M4量产工程实战

weixin_29189363的博客 236

基于STM32的智能火灾报警系统设计:多传感器融合与远程控制实现

本文详细介绍基于STM32单片机的智能火灾报警系统设计,采用多传感器融合技术(烟雾、温度、火焰检测)实现高精度火灾识别。系统集成远程控制与手机APP监控,通过加权决策算法降低误报率,提供多级响应策略,确保火灾预警的准确性与可靠性。

u5v6w7的博客 1102

C语言qsort函数

这里有关于C语言里的qsort函数的一些知识

qq_69383179的博客 1060

ServiceNow Discovery & CMDB Interview Questions and Answers (2025)

【代码】ServiceNow Discovery & CMDB Interview Questions and Answers (2025)

weixin_47584092的博客 910

C语言之——快速排序qsort库函数的讲解

C语言中对qsort快速排序函数的详解

weixin_69283129的博客 2906

别再只画GO图了!用R语言+Perl脚本搞定单细胞KEGG富集分析与圈图(附完整代码)

本文详细介绍了如何利用R语言和Perl脚本实现单细胞KEGG富集分析全流程,从基因ID转换到专业圈图可视化。通过对比KEGG与GO分析的互补价值,提供完整的代码实现和优化技巧,帮助研究者高效完成单细胞测序数据的通路分析,并生成高质量的圈图展示结果。

weixin_28694169的博客 403

用 ADT 连接 SAP S/4HANA Public Cloud 开发租户的完整落地指南

摘要:在SAP S/4HANA公有云中进行ABAP开发时,必须使用Development Tenant(客户端080)而非Customizing Tenant(客户端100)连接ADT工具。开发用户需具备SAP_BR_DEVELOPER角色且写权限不受限,开发对象应创建在结构包的子包中。连接前需确认正确的ABAP服务URL(通常为Launchpad URL去掉"/ui"),并通过运行控制台程序验证全链路功能。典型开发场景如通过BAdI实现业务校验时,需遵循Clean Core原则在指定包

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 336

[C]qsort的使用和实现

介绍qsort的使用和冒泡排序,详解了如何使用冒泡排序模拟实现qsort

qq_59456417的博客 2423

《UDS协议从入门到精通》系列——图解0x19:读取故障码信息

认识最核心的诊断服务“0x19”!!全网最强图解!一文搞懂所有常用子服务!

车载系统攻城狮 1万+

深度探索C语言的qsort:快速排序的艺术与实践

qsort 是 C 语言中一个强大且灵活的排序工具。通过提供自定义的比较函数,我们可以对各种数据类型的数组进行排序。掌握 qsort 的用法,可以让我们的编程工作更加高效。希望本文能够帮助你更好地理解和运用 qsort 函数。

平凡程序猿~的博客 1859

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

C语言之qsort函数

qsort函数

遇见的博客 1034

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

qsort — c语言中自带的排序函数(附带void*、回调函数知识点

介绍qsort函数,void*、回调函数等相关知识点。

vpurple_的博客 2014

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

【C语言】回顾qsort排序

qsort排序

来杯茶_要绿的的博客 233

qsort

qsort函数 定义:快速排序任意类型数据库函数。 头文件:&amp;lt;stdlib.h&amp;gt; qsort函数原型: void qsort(void *base,size_t num,size_t width,int (*compare)(const void *,const void *)) 各参数含义: (1)base是待排序数组首元素地址; (2)num是数组大小 (3)width是各元素占用...

weixin_42617262的博客 3384

C语言学习系列-->【关于qsort函数的详解以及它的模拟实现】

对数组的元素进行排序对数组中由 指向的元素进行排序,每个元素字节长,使用该函数确定顺序。此函数使用的排序算法通过调用指定的函数来比较元素对,并将指向它们的指针作为参数。qsort函数的参数void* basesize_t numvoid qsort(void* base, //待排序数据的起始位置size_t num, //待排序数据的元素个数size_t size,//待排序数据的每个元素的大小//函数指针 - 指针指向的函数是用来比较待排序数据中两个元素大小关系的。

Giggins GaoBlog 867

C语言快速排序--qsort函数

C语言快速排序–qsort函数 一.什么是qsort函数 qsort函数是C语言编译器函数库自带的快速排序函数。 其包含在#include<stdlib.h>头文件里面,所以在使用的时候需要加上该头文件。 二.qsort函数的时间复杂度 因为其本身还是快速排序,所以时间复杂度仍然是O(nlongn) (在洛谷做题的时候,感觉它还是比传统的快排要更快,传统的快排最后三个会TLE,但是使用...

weixin_45843077的博客 5520

冒泡排序和qsort函数详解以及如何模拟实现qsort函数

一.冒泡排序 冒泡排序是一种常见的排序方式,它可以把数组元素有序或无序的数组进行重新排序,并使得数组中的元素从大到小或从小到大进行排序(就像泡泡一样)。 冒泡排序原理: 每次比较数组中的相邻的两个元素的值,将较小的元素排在较大的元素的前面,就可实现数组元素从小到大排序;每次将较大的元素排在较小的元素的前面,就可实现数组元素从大到小排序。 以数字1,2,7,3,9,6为例,使其从大到小排序 · ...

m0_63037816的博客 1450

排序算法还在手写?万能排序神器qsort函数,搞定90%笔试面试!

排序算法还在手写?万能排序神器qsort函数,搞定90%笔试面试!

萧邯嵌入式笔记 1161

c语言qsort排序数组,求助,qsort排序字符串

该楼层疑似违规已被系统折叠隐藏此楼查看此楼没用过qsort,我也有点晕,好在搞清楚了,一会a,一会b,形参也用a,b容易搞混。其实程序里是两个逻辑块。一个是char * a[],一个是char b[][]qsort的原理是排序数组,compare是用来比较元素的函数入口。为什么qsort里调用d能排序b里的字符串,看前三个参数b, sizeof(b) / sizeof(*b), sizeof(*...

weixin_35767799的博客 375

C语言的回调函数(详解qsort函数)

对于自行构造出一个函数并使它实现qsort的功能,首先我们需要写出函数接收的参数,而参数并不需要什么多余思考,我们只需要借鉴qsort函数的参数就好了。但是我们需要思考一下:为什么传进BubbleSort函数中的base要定义成void*类型呢?这是因为想要实现为不同类型的数据进行排序,就要能够做到对各种类型的数据进行接收,如果我们在这里只是单一的写成int*,那么就无法对char*类型进行接收,如果写成char*,又无法对结构体类型进行接收,而void * 为"无类型指针"

爱是小小的癌的博客 2054

C语言学习记录(二)冒泡排序以及排序进阶

qsort函数排序和冒泡排序

m0_59183289的博客 419

【C语言】详细解读qsort()函数

目录一、qsort()函数简介 一、qsort()函数简介 [注]:部分转自菜鸟教程 void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))            头文件:stdlib.h          &nb

823
上一篇: Python入门速成:从 0 到会写题
下一篇: Web前端开发技术综述
Random_0_5
博客等级 码龄2年 201粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值