【万能排序之qsort、b_sort 、s_sort】
文章目录
- 前言
- :star:qsort函数
- 函数参数
- qsort函数的使用
- :star:模拟实现万冒泡排序
- 函数参数
- 模拟实现b_sort
- 注意点
- :star:模拟实现万能选择排序
- 函数参数
- 模拟实现s_sort
- 最后
前言
我们所熟悉的冒泡排序,选择排序,插入排序,二分排序等都是基于给定的一种类型进行排序,
通用性不强,但是库函数qsort可以对任意类型的数据包括字符串、结构体等进行排序,所以本章内容是了解qsort函数的使用方法和大致思想以及通过模仿qsort函数自己写出万能的排序
⭐️qsort函数
函数参数


现在我们应该清楚几点
- qsort函数有四个参数,第一个参数是待排序数组首元素的地址,因为不清楚具体是什么类型,所以用`void*``接受
- 第2个参数是数组的元素个数,第3个参数是数组元素的字节数
- 第4个参数是一个指向用户自己实现的函数的指针,用户实现的函数需要告诉qsort函数一个数据怎么样才算大于另一个数据
- 用户自己实现的函数形参是两个
void*的指针,在具体比较2个数据时,用户自己知道带比较元素是什么类型的,所以需要对void*的指针进行强制类型转化
qsort函数的使用
qsort排序整形数组
void PrintArr(int* arr, int sz)
{for (int i = 0; i < sz; i++)printf("%d ", arr[i]);printf("\n");
}
//自定义比较2个整形的函数int CompareInt(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2; //需要对void*类型的指针进行强制转换为需要比较元素的类型,因为void*指针无法解引用
}
int main()
{int arr[5] = { 5, 4, 3 ,2 ,1 };qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), CompareInt);PrintArr(arr, sizeof(arr) / sizeof(arr[0]));return 0;
}

qsort排序结构体数组
typedef struct
{char name[10];int age;
}s;//自定义比较结构体数组元素年龄的函数
int CompareByAge(const void* e1, const void* e2)
{return ((s*)e1)->age - ((s*)e2)->age;
}
//自定义比较结构体数组元素姓名的函数
int CompareByName(const void* e1, const void* e2)
{return strcmp(((s*)e1)->name, ((s*)e2)->name);
}void PrintArrAge(s* stu, int sz)
{for (int i = 0; i < sz; i++)printf("%d ", stu[i].age);printf("\n");
}void PrintArrName(s* stu, int sz)
{for (int i = 0; i < sz; i++)printf("%s ", stu[i].name);printf("\n");
}int main()
{s stu[3] = { {"zhangsan",10 }, {"lisi",20}, {"wangwu", 30} };qsort(stu, 3, sizeof(stu[0]), CompareByAge);PrintArrAge(stu, sizeof(stu) / sizeof(stu[0]));qsort(stu, 3, sizeof(stu[0]), CompareByName);PrintArrName(stu, sizeof(stu) / sizeof(stu[0]));return 0;
}

注:在自定义排序函数时,将e1转换为结构体指针需要将e1也用括号括
((s*)e1)起来因为->的优先级较高
⭐️模拟实现万冒泡排序
函数参数

模拟实现b_sort
void swap(char* buf1, char* buf2, size_t width)
{//因为不知道具体需要交换的数据的类型,所以需要传递第三个参数数据的字节数width//一个字节一个字节的交换,交换width次后,代表已经将这两个数据交换完成for (size_t i = 0; i < width; i++){int tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}
void b_sort(void* base, size_t num, size_t width, int (*compare)(const void* e1, const void* e2))
{for (size_t i = 0; i < num - 1; i++)//一趟冒泡排序{int flag = 1; //flag为1表示数组是有序的for (size_t j = 0; j < num - 1 - i; j++){//比较数组中两个相邻的元素,因为不知道元素的类型,所以需要调用用户自定义的比较函数if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0){flag = 0;//交换两个数,保证在前面的数比后面的数更小swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}//说明数组已经是有序的if (flag == 1)break;}
}int CompareInt(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}
int main()
{int arr[5] = { 5 , 4, 3, 2 ,1 };b_sort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(arr[0]), CompareInt);PrintArr(arr, sizeof(arr) / sizeof(arr[0]));
}

注意点
- 想要冒泡排序可以排任何类型数据时,不需要改变冒泡排序的算法,只需要改变比较的原理,以及如何交换两个数,因为开发者在写b_sort时不知道调用者会比较哪些数据类型,所以在编写b_sort时需要将比较方法改成通用的,而这个比较方法需要知道比较数据类型的调用者自己实现
- 在swap函数中,开发者并不知道调用者需要交换的数据类型,所以开发者需要知道调用者交换数据类型的字节数width,这样不管是什么类型,只要将需要交换的两个数据每一个字节数都交换,交换width次,最后的是两个数一定已经交换了
- 在b_sort函数中的compare函数,因为我不知道需要比较的数据的类型,所以不能够知道需要跳过多少字节才到下一个数组元素,因此需要调用这传递参数width来告诉开发者比较下一个元素时要跳过width个字节数,+width跳过width个字节数的前提就是e1,e2必须强转为
char*类型指针
⭐️模拟实现万能选择排序
函数参数

模拟实现s_sort
代码
void swap(char* buf1, char* buf2, size_t width)
{//因为不知道具体需要交换的数据的类型,所以需要传递第三个参数数据的字节数width//一个字节一个字节的交换,交换width次后,代表已经将这两个数据交换完成for (size_t i = 0; i < width; i++){int tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}
}
void s_sort(void* base, size_t num, size_t width, int (*compare)(const void* e1, const void* e2))
{//循环n-1次for (size_t i = 0; i < num - 1; i++){//min指向base[i]char* min = (char*)base + i * width;for (size_t j = i + 1; j < num; j++){//min > arr[j]if (compare(min, (char*)base + j * width) > 0){min = (char*)base + j * width;}}if (min != (char*)base + i * width)swap((char*)base + i * width, min, width);}
}
提醒
选择函数的实现也是主要算法没有改变,但是除了比较数据的方法和交换数据的方法改变了,还有min定义为char*类型指针,这样方便后续min直接参加算术运算
最后
个人认为弄清qsort函数的使用原理是很重要的,这种思想我认为值得参考,有兴趣的话可以将其他的排序算法也改写成万能排序
😄如果这期内容对你有帮助,希望你能够给一个免费的三连⭐️⭐️⭐️😄
相关文章:
【万能排序之qsort、b_sort 、s_sort】
文章目录前言:star:qsort函数函数参数qsort函数的使用:star:模拟实现万冒泡排序函数参数模拟实现b_sort注意点:star:模拟实现万能选择排序函数参数模拟实现s_sort最后前言 我们所熟悉的冒泡排序,选择排序,插入排序,二分排序等都是基于给定的一…...
利用InceptionV3实现图像分类
最近在做一个机审的项目,初步希望实现图像的四分类,即:正常(neutral)、涉政(political)、涉黄(porn)、涉恐(terrorism)。有朋友给推荐了个github上…...
【Java】CAS锁
一、什么是CAS机制(compare and swap) 1.概述 CAS的全称为Compare-And-Swap,直译就是对比交换。是一条CPU的原子指令,其作用是让CPU先进行比较两个值是否相等,然后原子地更新某个位置的值。经过调查发现,…...
Linux服务器配置系统安全加固方法
1. SSH空闲超时时间建议为: 600-900 解决方案: 在【/etc/ssh/sshd_config】文件中设置【ClientAliveInterval】设置为600到900之间 vim /etc/ssh/sshd_config #将 ClientAliveInterval 参数值设置为 900 2. 修改检查SSH密码修改最小间隔 解决方案: 在【/etc/login.defs】文件…...
Codeforces Round #850 (Div. 2, based on VK Cup 2022 - Final Round)(A~E)
t宝酱紫喜欢出这种分类讨论的题?!A1. Non-alternating Deck (easy version)给出n张牌,按照题目给的顺序分给两人,问最后两人手中各有几张牌。思路:模拟。AC Code:#include <bits/stdc.h>typedef long…...
qt源码--信号槽
本篇主要从Qt信号槽的连接、断开、调用、对象释放等方面展开; 1.信号建立连接过程 connect有多个重载函数,主要是为了方便使用者,比较常用的有2种方式: a. QObject::connect(&timer, &QTimer::timeout, &loop, &am…...
RecycleView详解
listview缓存请看: listview优化和详解RecycleView 和 ListView对比:使用方法上ListView:继承重写 BaseAdapter,自定义 ViewHolder 与 converView优化。RecyclerView: 继承重写 RecyclerView.Adapter 与 RecyclerView.ViewHolder。设置 Layou…...
【算法】最短路算法
😀大家好,我是白晨,一个不是很能熬夜😫,但是也想日更的人✈。如果喜欢这篇文章,点个赞👍,关注一下👀白晨吧!你的支持就是我最大的动力!Ǵ…...
< Linux > 进程间通信
目录 1、进程间通信介绍 进程间通信的概念 进程间通信的本质 进程间通信的分类 2、管道 2.1、什么是管道 2.2、匿名管道 匿名管道的原理 pipe函数 匿名管道使用步骤 2.3、管道的读写规则 2.4、管道的特点 2.5、命名管道 命名管道的原理 使用命令创建命名管道 mkfifo创建命名管…...
学习 Python 之 Pygame 开发魂斗罗(二)
学习 Python 之 Pygame 开发魂斗罗(二)魂斗罗的需求开始编写魂斗罗1. 搭建主类框架2. 设置游戏运行遍历和创建窗口3. 获取窗口中的事件4. 创建角色5. 完成角色更新函数魂斗罗的需求 魂斗罗游戏中包含很多个物体,现在要对这些物体进行总结 类…...
户籍管理系统测试用例
目录 一、根据页面的不同分别设计测试用例 登录页面 用户信息列表 用户编辑页面 用户更新页面 二、根据目的不同分别设计测试用例 一、根据页面的不同分别设计测试用例 上图是针对一个网站的测试,按照页面的不同分别来设计对应的测试用例。 登录页面 用户信息列…...
(三)代表性物质点邻域的变形分析
本文主要内容如下:1. 伸长张量与Cauchy-Green 张量2. 线元长度的改变2.1. 初始/当前构型下的长度比2.2. 主长度比与 Lagrange/Euler 主方向2.3. 初始/当前构型下任意方向的长度比3. 线元夹角的改变4. 面元的改变5. 体元的改变1. 伸长张量与Cauchy-Green 张量 由于变…...
Stream操作流 练习
基础数据:Data AllArgsConstructor NoArgsConstructor public class User {private String name;private int age;private String sex;private String city;private Integer money; static List<User> users new ArrayList<>();public static void m…...
【模拟集成电路】宽摆幅压控振荡器(VCO)设计
鉴频鉴相器设计(Phase Frequency Detector,PFD)前言一、VCO工作原理二、VCO电路设计VCO原理图三、压控振荡器(VCO)测试VCO测试电路图瞬态测试(1)瞬态输出(2)局部放大图&a…...
《英雄编程体验课》第 13 课 | 双指针
文章目录 零、写在前面一、最长不重复子串1、初步分析2、朴素算法3、优化算法二、双指针1、算法定义2、算法描述3、条件1)单调性2)时效性三、双指针的应用1、前缀和问题2、哈希问题3、K 大数问题零、写在前面 该章节节选自 《夜深人静写算法》,主要讲解最基础的枚举算法 ——…...
DS期末复习卷(十)
一、选择题(24分) 1.下列程序段的时间复杂度为( A )。 i0,s0; while (s<n) {ssi;i;} (A) O(n^1/2) (B) O(n ^1/3) © O(n) (D) O(n ^2) 12…xn xn^1/2 2.设某链表中最常用的…...
QT+OpenGL模板测试和混合
QTOpenGL模板测试和混合 本篇完整工程见gitee:QtOpenGL 对应点的tag,由turbolove提供技术支持,您可以关注博主或者私信博主 模板测试 当片段着色器处理完一个片段之后,模板测试会开始执行。和深度测试一样,它可能会丢弃片段&am…...
《英雄编程体验课》第 11 课 | 前缀和
文章目录 零、写在前面一、概念定义1、部分和2、朴素做法3、前缀和4、前缀和的边界值5、边界处理6、再看部分和二、题目描述1、定义2、求解三、算法详解四、源码剖析五、推荐专栏六、习题练习零、写在前面 该章节节选自 《算法零基础100讲》,主要讲解最基础的算法 —— 前缀和…...
Java学习--多线程2
2.线程同步 2.1卖票【应用】 案例需求 某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票 实现步骤 定义一个类SellTicket实现Runnable接口,里面定义一个成员变量:privat…...
【Virtualization】Windows11安装VMware Workstation后异常处置
安装环境 Windows 11 专业版 22H2 build 22621.1265 VMware Workstation 17 Pro 17.0.0 build-20800274 存在问题 原因分析 1、BIOS未开启虚拟化。 2、操作系统启用的虚拟化与Workstation冲突。 3、操作系统启用内核隔离-内存完整性保护。 处置思路 1、打开“资源管理器”…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
从零实现STL哈希容器:unordered_map/unordered_set封装详解
本篇文章是对C学习的STL哈希容器自主实现部分的学习分享 希望也能为你带来些帮助~ 那咱们废话不多说,直接开始吧! 一、源码结构分析 1. SGISTL30实现剖析 // hash_set核心结构 template <class Value, class HashFcn, ...> class hash_set {ty…...


