【C语言】qsort详解——能给万物排序的神奇函数

🦄个人主页:小米里的大麦-CSDN博客

🎏所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html

⚙️操作环境:Visual Studio 2022

目录

一、引言

二、qsort函数介绍

1.函数原型

2.参数说明

2.1比较函数

3.使用示例

3.1对一维数组进行排序 

3.2对结构体进行排序 

4.让我们尝试用更简单的方式来说明如何使用 qsort 函数。

步骤 1: 定义比较函数

步骤 2: 调用 qsort 函数

5.进阶 

5.1 解释:

1. 参数:

2. 返回值:

2. 实现细节:

5.2 为什么自动排序?

1. 减法操作

2.qsort 排序机制

3. 实现细节

三、模拟实现qsort函数

使用bubble_sort函数

四、总结

五、共勉


一、引言

在C语言中,qsort函数是一个非常强大且灵活的排序工具,它能够处理各种不同类型的数据结构,包括基本类型数组、字符串、二维数组甚至是结构体。本篇文章将详细介绍qsort函数的工作原理以及如何使用它来进行排序。

二、qsort函数介绍

qsort函数是C标准库中的一个通用排序函数,它的原型定义在stdlib.h头文件中。qsort函数之所以被称为“快速排序”函数,是因为它通常采用了一种高效的排序算法——快速排序算法来实现排序过程。

来看看qsort - C++ Reference上的介绍:

1.函数原型

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

2.参数说明

  • base:指向待排序数组的指针。(谁需要排序)
  • num:数组中元素的数量。(需要排序的数量/有多少数需要排序)
  • size:数组中每个元素的字节数。(每个元素有多大)
  • compar:指向一个比较函数的指针,该函数用于确定排序顺序。(比较函数的指针)

2.1比较函数

比较函数compar接受两个void *类型的参数,并返回一个int类型的值。如果第一个参数应该排在第二个参数之前,则返回负数;如果两者相等,则返回0;如果第一个参数应该排在第二个参数之后,则返回正数。

3.使用示例

让我们通过几个例子来看看如何使用qsort函数。

3.1对一维数组进行排序 

#include <stdio.h>
#include <stdlib.h>int compar(const void *a, const void *b) {return *(int *)a - *(int *)b;
}int main() {int arr[] = {3, 1, 5, 9, 7, 6, 4, 8, 0, 2};size_t num = sizeof(arr) / sizeof(arr[0]);size_t sz = sizeof(arr[0]);qsort(arr, num, sz, compar);for (int i = 0; i < num; i++) {printf("%d ", arr[i]);}return 0;
}

3.2对结构体进行排序 

按年龄排序
#include <stdio.h>
#include <stdlib.h>struct Stu {char name[20];int age;
};int compar_Stu_age(const void *p1, const void *p2) {return ((struct Stu *)p1)->age - ((struct Stu *)p2)->age;
}int main() {struct Stu s[] = {{"zhangsan", 20}, {"lisi", 30}, {"wangmazi", 25}};size_t num = sizeof(s) / sizeof(s[0]);size_t sz = sizeof(s[0]);qsort(s, num, sz, compar_Stu_age);for (int i = 0; i < 3; i++) {printf("%s, %d\n", s[i].name, s[i].age);}return 0;
}
按姓名排序
int compar_Stu_name(const void *p1, const void *p2) {return strcmp(((struct Stu *)p1)->name, ((struct Stu *)p2)->name);
}int main() {struct Stu s[] = {{"zhangsan", 20}, {"lisi", 30}, {"wangmazi", 25}};size_t num = sizeof(s) / sizeof(s[0]);size_t sz = sizeof(s[0]);qsort(s, num, sz, compar_Stu_name);for (int i = 0; i < 3; i++) {printf("%s, %d\n", s[i].name, s[i].age);}return 0;
}

4.让我们尝试用更简单的方式来说明如何使用 qsort 函数。

假设我们有一个整数数组,我们想要按升序排序这个数组。首先我们需要定义一个比较函数,然后调用 qsort 函数。

步骤 1: 定义比较函数

比较函数用来告诉 qsort 如何比较数组中的元素。对于整数数组,我们可以这样定义比较函数:

int compare(const void *a, const void *b) {if (*(int *)a < *(int *)b) {return -1;  // a 小于 b} else if (*(int *)a > *(int *)b) {return 1;   // a 大于 b} else {return 0;   // a 等于 b}
}

这里的关键点是,ab 是指向 void 类型的指针,我们需要把它们转换成指向 int 的指针,以便能够访问它们所指向的整数值。

步骤 2: 调用 qsort 函数

接下来,我们可以在 main 函数中定义一个整数数组,并调用 qsort 函数对其进行排序。

#include <stdio.h>
#include <stdlib.h>// 比较函数
int compare(const void *a, const void *b) {if (*(int *)a < *(int *)b) {return -1;  // a 小于 b} else if (*(int *)a > *(int *)b) {return 1;   // a 大于 b} else {return 0;   // a 等于 b}
}int main() {int arr[] = {5, 2, 9, 1, 5, 6};int n = sizeof(arr) / sizeof(arr[0]);  // 计算数组元素个数// 调用 qsort 函数qsort(arr, n, sizeof(int), compare);// 输出排序后的数组printf("Sorted array: ");for (int i = 0; i < n; i++) {printf("%d ", arr[i]);}printf("\n");return 0;
}

5.进阶 

// 定义比较函数
int compare(const void *a, const void *b) {return (*(int *)a - *(int *)b);
}

比较函数通常写成return (*(int *)a - *(int *)b);这种方法适用于整数数组的排序,但如果你需要对其他数据类型进行排序或者需要更复杂的比较逻辑,就需要修改这个函数以适应你的需求。

5.1 解释:

这个函数实现了以下功能:

1. 参数:
  • const void *a: 指向第一个要比较的元素的指针。
  • const void *b: 指向第二个要比较的元素的指针。
2. 返回值:
  • 如果 *(int *)a 小于 *(int *)b,则返回一个负数。
  • 如果 *(int *)a 等于 *(int *)b,则返回 0。
  • 如果 *(int *)a 大于 *(int *)b,则返回一个正数。
3. 实现细节:
  • *(int *)a 和 *(int *)b 分别将 void 指针转换为 int 指针,并解引用这些指针以获取实际的整数值。
  • *(int *)a - *(int *)b 进行减法运算,得到的结果直接作为函数的返回值。

这种实现方式非常简洁,通过减法操作自动处理了所有三种情况:

  • 如果结果是负数,则 a 应该排在 b 前面。
  • 如果结果是 0,则 a 和 b 相等。
  • 如果结果是正数,则 a 应该排在 b 后面。

5.2 为什么自动排序?

1. 减法操作

当执行 *(int *)a - *(int *)b 时,实际上是在计算两个整数值之间的差。这个差可以是正数、负数或零,这取决于 ab 的相对大小。

  • 如果 *(int *)a < *(int *)b,那么差值将会是一个负数。
  • 如果 *(int *)a == *(int *)b,那么差值将会是零。
  • 如果 *(int *)a > *(int *)b,那么差值将会是一个正数。

2.qsort 排序机制

qsort 函数通过比较函数来确定元素的相对顺序。比较函数需要返回一个整数值来指示两个元素的相对位置关系。具体来说:

  • 如果比较函数返回一个负数,qsort 函数会认为 a 应该排在 b 的前面。
  • 如果比较函数返回零,qsort 函数会认为 a 和 b 的位置无关紧要,因为它们相等或不需要交换。
  • 如果比较函数返回一个正数,qsort 函数会认为 a 应该排在 b 的后面。

3. 实现细节

由于 qsort 函数内部的排序算法(通常是快速排序或其他高效算法)需要知道如何比较两个元素,所以它会调用提供的比较函数,并根据返回值决定如何排列元素。

三、模拟实现qsort函数

除了使用标准库中的qsort函数,我们还可以自己模拟实现一个类似的排序函数,比如使用冒泡排序算法。下面是一个简单的冒泡排序实现,它能够对不同的数据类型进行排序。

冒泡排序实现
#include <stdio.h>
#include <stdlib.h>void Swap(char *buf1, char *buf2, int sz) {int i;for (i = 0; i < sz; i++) {char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}void bubble_sort(void *base, size_t num, size_t sz, int (*compar)(const void *, const void *)) {size_t i, j;for (i = 0; i < num - 1; i++) {for (j = 0; j < num - 1 - i; j++) {if (compar((char *)base + j * sz, (char *)base + (j + 1) * sz) > 0) {Swap((char *)base + j * sz, (char *)base + (j + 1) * sz, sz);}}}
}

使用bubble_sort函数

使用bubble_sort函数与使用qsort函数类似,都需要提供相同的参数。这里不再重复给出示例代码。

四、总结

qsort函数是一个非常有用的工具,它提供了高度灵活的排序能力。通过自定义比较函数,我们可以轻松地对不同类型的数据进行排序。此外,通过上面的示例可以看出,即使使用简单的冒泡排序算法也能实现类似的功能,尽管在性能上可能不如qsort函数高效。

希望这篇文章对你理解和使用qsort函数有所帮助!

五、共勉

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3280513.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【Canvas与艺术】五色五角大楼

【成图】 【代码】 <!DOCTYPE html> <html lang"utf-8"> <meta http-equiv"Content-Type" content"text/html; charsetutf-8"/> <head><title>五L莫比乌斯五角大楼</title><style type"text/css&qu…

芋道以开源之名行下作之事 恬不知耻 标榜自己开源 公开源码+sql 不用再加入知识星球

资源 链接: https://pan.baidu.com/s/1TeuxbAUfLQ5_BqMBF1kniQ?pwdcqud 提 取码: cqud 依次为后端、补充版的sql、前端 此文档内安装部署等一应俱全

科普文:深入理解ElasticSearch体系结构

概叙 Elasticsearch是什么&#xff1f; Elasticsearch&#xff08;简称ES&#xff09;是一个分布式、可扩展、实时的搜索与数据分析引擎。ES不仅仅只是全文搜索&#xff0c;还支持结构化搜索、数据分析、复杂的语言处理、地理位置和对象间关联关系等。 官网地址&#xff1a;…

MSA+抑郁症模型总结(一)(论文复现)

MSA抑郁症模型总结&#xff08;一&#xff09;&#xff08;论文复现&#xff09; 本文所涉及所有资源均在传知代码平台可获取 文章目录 MSA抑郁症模型总结&#xff08;一&#xff09;&#xff08;论文复现&#xff09;情感分析在多场景的应用一、概述二、论文地址三、研究背景四…

PyTorch 2.0中图像增强方法详解

【图书推荐】《PyTorch深度学习与计算机视觉实践》-CSDN博客 基于Vision Transformer的mini_ImageNet图片分类实战_imagenet数据集-CSDN博客 Vision Transformer模型是目前图形识别领域最为前沿的和性能最好的图形分类模型&#xff0c;它能够对目标图像做出准确度最高的判断。…

《动手做科研 》| 05. 如何开展和记录实验

地址链接:《动手做科研》05. 如何开展和记录实验 导读: 当我们开始训练多个具有不同超参数的模型&#xff0c;我们就需要对实验开始进行管理。我们将其分为三个部分&#xff1a;实验追踪、超参数搜索和配置设置。我们将使用 Weights & Biases 来演示实验记录和追踪&#xf…

支持AI的好用的编辑器aieditor

一、工具概述 AiEditor 是一个面向 AI 的下一代富文本编辑器&#xff0c;她基于 Web Component&#xff0c;因此支持 Layui、Vue、React、Angular 等几乎任何前端框架。她适配了 PC Web 端和手机端&#xff0c;并提供了 亮色 和 暗色 两个主题。除此之外&#xff0c;她还提供了…

【源码+文档+调试讲解】乡镇篮球队管理系统设计与实现

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本乡镇篮球队管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信…

基础篇| 全网最全详解12个大模型推理框架

01 什么是框架? 开始介绍之前, 我们先了解一下什么是框架?xx框架-IT人经常听到的名词。但是又有多少人知道框架的意思? 框架&#xff08;framework&#xff09;是一个框子:指其约束性&#xff0c;也是一个架子——指其支撑性。是一个基本概念上的结构&#xff0c;用于去解…

新作品,一个通用的 Cloudflare Workers HTTP 反向代理

本文介绍我最近写的新作品&#xff1a;使用 Cloudflare Workers/Pages 搭建 HTTP 反向代理&#xff0c;代码已经全部开源在 GitHub&#xff0c;按照 README 里面的脚本搭建就可以了&#xff0c;非常简单。 GitHub&#xff1a;https://github.com/jonssonyan/cf-workers-proxy …

数字图像处理 第三章 灰度变换和空间滤波(上)

文章目录 本章简介一、背景知识 P62 - P641.1 灰度变换和空间滤波基础 P62 - P63二、一些基本的灰度变换函数 P64 - P712.1 图像反转 P642.2 对数变换 P64 - P662.3 幂律(伽马变换 P66 - P682.4 分段线性变换函数 P68 - P71本章知识点总结本章简介 本章讨论在空间域中的图像增强…

【C/C++】关于 extern “C“ 的理解

详细解释 #ifdef __cplusplus extern "C" 在C中&#xff0c;#ifdef __cplusplus 和 extern "C" 是用于处理C和C混合编程中的名称修饰&#xff08;name mangling&#xff09;问题的预处理器指令和关键字。 #ifdef __cplusplus __cplusplus 是一个预处理器…

人工智能大模型发展带来的风险挑战和对策

经过近70年的发展&#xff0c;人工智能技术发展经历了三次起伏&#xff0c;2022年以来&#xff0c;以ChatGPT、Sora等为代表的预训练大模型持续取得突破&#xff0c;推动着人工智能技术从感知向认识&#xff0c;从分析判断式向生成式&#xff0c;从专用向通用进入快速发展的新阶…

PythonDjangoMysql外卖app系统32762-计算机毕业设计项目选题推荐(附源码)

摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;餐饮外卖当然也不例外。 外卖app系统主要功能模块包括后台首页&#xff0c;轮播图&#xff0c;资源管理&#xff08;餐饮…

【CTFWP】ctfshow-web40

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 题目介绍&#xff1a;题目分析&#xff1a;payload&#xff1a;payload解释&#xff1a;payload2&#xff1a;payload2解释&#xff1a;flag 题目介绍&#xff1a; …

高等数学 第七讲 一元函数积分学的概念和性质_不定积分_定积分_变限积分_反常积分

1.不定积分 文章目录 1.不定积分1.1 原函数1.1.1 原函数与不定积分的定义1.1.2 原函数存在定理 2.定积分2.1 定积分的定义2.2 定积分的精确定义2.3 定积分的几何意义2.4 定积分的存在定理2.5 定积分的性质 3.变限积分3.1 变限积分的定理3.2 变限积分的性质 4.反常积分(待更新) …

红酒标签设计:艺术与品味的结合

在红酒的世界里&#xff0c;每一瓶酒都如同一位优雅的舞者&#xff0c;在酒柜的舞台上静静诉说着自己的故事。而红酒的标签&#xff0c;则是这位舞者身上较华丽的舞裙&#xff0c;它不仅是红酒的身份证明&#xff0c;更是艺术与品味的很好结合。今天&#xff0c;我们就来聊聊红…

重载云台摄像机如何通过国标28181接入到统一视频接入平台(视频国标接入平台)

目录 一、国标GB/T 28181介绍 1、国标GB/T28181 2、内容和特点 二、重载云台摄像机 1、定义 2、结构与设计 3、功能和优势 4、特点 5、应用场景 二、接入准备工作 1、确定网络环境 &#xff08;1&#xff09;公网接入 &#xff08;2&#xff09;专网传输 2、检查重…

STC单片机UART映射printf

文章目录 使用STC-ISP生成UART初始化函数 增加如下函数&#xff0c;注意使用printf函数需要添加 #include <stdio.h> 头文件 #include <stdio.h>void Uart1_Init(void) //9600bps12.000MHz {SCON 0x50; //8位数据,可变波特率AUXR | 0x01; //串口1选择定时器2为…

Vue2从基础到实战(v-bind对于样式控制的增强-操作style,v-model在其他表单元素的使用)

v-bind对于样式控制的增强-操作style 语法&#xff1a;style"样式对象" <div class"box" :style"{ CSS属性名1: CSS属性值, CSS属性名2: CSS属性值 }"></div> 代码解析&#xff1a; HTML结构&#xff1a; 包含了一个div元素&…