当前位置: 首页 > news >正文

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

在这里插入图片描述

文章目录

  • 一、概述
  • 二、qsort函数参数介绍
  • 三、qsort实现排序
    • 3.1 qsort实现整型数组排序
    • 3.2 qsort实现结构体数组排序
  • 四、模拟实现qsort函数

一、概述

对数组的元素进行排序
对数组中由 指向的元素进行排序,每个元素字节长,使用该函数确定顺序。
此函数使用的排序算法通过调用指定的函数来比较元素对,并将指向它们的指针作为参数。

官方解释:

在这里插入图片描述

声明:

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

qsort函数的参数

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

二、qsort函数参数介绍

void qsort(void* base, //待排序数据的起始位置size_t num, //待排序数据的元素个数size_t size,//待排序数据的每个元素的大小int (*compar)(const void*p1, const void*p2));//函数指针 - 指针指向的函数是用来比较待排序数据中两个元素大小关系的

关于void * 的介绍:
void * 是一个无具体指向的指针类型
任何类型的指针变量都i可以存放在void中
void * 不能解引用

其中两个void*类型的参数 p1 和 p2 用来存放数组中待比较的两个元素的地址。如果compar函数的返回值小于0,会把p1指向的元素排到p2指向的元素前面;如果返回值等于0,不会改变p1和p2指向的元素位置;如果返回值大于0,会把p1指向的元素排到p2指向的元素后面。

三、qsort实现排序

3.1 qsort实现整型数组排序

# define _CRT_SECURE_NO_WARNINGS#include<stdio.h>
#include<stdlib.h>int comper(const void* e1, const void* e2)
{//通过强制类型转换,比较e1,e2.return *(int*)e1 - *(int*)e2;//void* 不能解引用
}int main()
{int arr[] = { 5,3,6,7,8,1,9,4,2,0 };int sz = sizeof(arr) / sizeof(arr[0]);//传入参数qsort(arr, sz, sizeof(arr[0]), comper);//打印排序后的数组int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}

在这里插入图片描述

3.2 qsort实现结构体数组排序

按照年龄大小的方式进行排序

# define _CRT_SECURE_NO_WARNINGS#include<stdio.h>
#include<stdlib.h>struct Stu
{char name[20];int age;
};int comper_by_age(const void* e1, const void* e2)
{return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;  //结构体指针不需要解引用
}int main()
{struct Stu s[] = { {"zhangsan",20},{"lisi",30},{"wangwu",25} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), comper_by_age);int i = 0;for (i = 0; i < sz; i++){printf("%s %d\n", s[i].name, s[i].age);}return 0;
}

运行结果:

zhangsan 20
wangwu 25
lisi 30

按照名字进行排序

# define _CRT_SECURE_NO_WARNINGS#include<stdio.h>
#include<stdlib.h>
#include<string.h>struct Stu
{char name[20];int age;
};int comper_by_name(const void* e1, const void* e2)
{return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e1)->name);//名字是字符串,通过strcmp函数来比较
}int main()
{struct Stu s[] = { {"zhangsan",20},{"lisi",30},{"wangwu",25} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), comper_by_name);int i = 0;for (i = 0; i < sz; i++){printf("%s %d\n", s[i].name, s[i].age);}return 0;
}

运行结果:

lisi 30
wangwu 25
zhangsan 20

在这里插入图片描述

四、模拟实现qsort函数

程序员A:写一个bubble_sort()函数,可以让别人直接拿来调用

于是程序员A想要利用冒泡排序的方式,来模拟实现qsort()函数排序

qsort的底层是通过快速排序来实现的

为了能对任意数组进行排序,程序员A对冒泡排序进行了一定的更改

和qsort函数一样,bubble_sort也需要传入四个参数:

void* arr   //接收首元素地址
size_t sz   //接收元素个数
size_t width  //接收元素宽度
int(*comper)(const void*e1,const void*e2)

于是,

void bubble_sort(void*arr,size_t sz,size_t width,int(*comper)(const void*e1,const void*e2))

现在需要完成bubble_sort内部,也就是实现排序

void bubble_sort(void* arr, size_t sz, size_t width, int(*comper)(const void* e1, const void* e2))
{size_t i = 0;//趟数for (i = 0; i < sz - 1; i++){//一趟冒泡排序的过程size_t j = 0;for (j = 0; j < sz - 1 - i; j++){/*............................ 		*/}}
}

在冒泡排序中,运用下面代码,使得相邻两个元素进行交换:

//每一轮冒泡要进行多少次两两比较if (arr[j] > arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}

但是,这只适用于整型,不通用

那么,如何去比较呢?如何去交换两个元素呢?

for (j = 0; j < sz-1-i; j++){if (comper((char*)arr+j*width,(char*)arr+(j+1)*width)>0)//把arr强转为char*,arr就可以正常使用//char类型指针+1只会跳过一个字节//+j*width表示跳过j个元素{//交换//由于这里的数组名已经被转为char类型的指针//所以要交换数组中的元素,就只能一个字节一个字节进行交换Swap((char*)arr + j * width, (char*)arr + (j + 1) * width,width);//前两个参数是待交换元素的地址,第三个参数是元素的宽度}}

这样,就把交换条件普适化了,不只是能用在整型类型中

那么…交换呢?

根据以前的经验,我们知道使得两个元素交换,可以引入一个新的变量来暂时存一下,从而去交换,但是这有限制。

解决方案:一个字节一个字节地交换

我们将交换地函数,封装在这里面:

Swap((char*)arr + j * width, (char*)arr + (j + 1) * width,width)

对Swap函数进行加工:

void Swap(char* ele1, char* ele2,int width)
{int i = 0;for (i = 0; i < width; i++){char tmp = *ele1;*ele1 = *ele2;*ele2 = tmp;ele1++;ele2++;}
}

这样,程序员A就将 bubble_sort()函数完成了

程序员B要想是使用该函数,直接引入 bubble_sort函数,自己写一个比较函数就可以了。

在这里插入图片描述

相关文章:

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

文章目录 一、概述二、qsort函数参数介绍三、qsort实现排序3.1 qsort实现整型数组排序3.2 qsort实现结构体数组排序 四、模拟实现qsort函数 一、概述 对数组的元素进行排序 对数组中由 指向的元素进行排序&#xff0c;每个元素字节长&#xff0c;使用该函数确定顺序。 此函数使…...

Linux系统安全:NAT(SNAT、DNAT)

目录 一.NAT 二.SNAT 三.DNAT 一.NAT NAT: network address translation&#xff0c;支持PREROUTING&#xff0c;INPUT&#xff0c;OUTPUT&#xff0c;POSTROUTING四个链 请求报文&#xff1a;修改源/目标IP&#xff0c; 响应报文&#xff1a;修改源/目标IP&#xff0c;根据…...

【数据库】MySQL存储过程:提升数据库性能和操作效率的利器

在数据库管理系统中&#xff0c;存储过程是一种重要的数据库对象&#xff0c;它允许将一组复杂的SQL语句组合起来&#xff0c;形成一个独立的单元进行重复使用。存储过程可以极大地提高数据库的性能和操作效率&#xff0c;降低网络流量&#xff0c;减轻系统负载。本文将深入探讨…...

rust写一个多线程和协程的例子

当涉及到多线程和协程时&#xff0c;Rust提供了一些非常强大的工具&#xff0c;其中最常用的库之一是tokio&#xff0c;它用于异步编程和协程。下面我将为你展示一个简单的Rust程序&#xff0c;演示如何使用多线程和协程。 首先&#xff0c;你需要在你的项目的Cargo.toml文件中…...

react18+antd5.x(1):Notification组件的二次封装

antdesign已经给我们提供了很好的组件使用体验,但是我们还需要根据自己的项目业务进行更好的封装,减少我们的代码量,提升开发体验 效果展示 开起来和官网的使用没什么区别,但是我们在使用的时候,进行了二次封装,更利于我们进行开发 MyNotification.jsx,是我们的业务页面…...

jenkins运行pytest测试用例脚本报错:没有权限,无法写日志PermissionError:[Error 13]Permission denied

报错信息&#xff1a; PermissionError:[Error 13]Permission denied&#xff1a;‘/var/jenkins_home/workspace/deleverySystem/Delivery_System/out_files/logs/waimai_20230823.log’ 解决方法&#xff1a; 在jenkins容器内部输入 chmod -R 777 /var/jenkins_home/works…...

数据结构 day1

1>x.mind 2>间接定义结构体数组&#xff0c;进行4种方式的定义和初始化 3>定义结构体存储10辆车&#xff08;车的信息&#xff1a;品牌、单价、颜色&#xff09; 1.定义函数&#xff0c;实现循环输入 2.定义函数&#xff0c;实现排序 3.定义函数&#xff0c;计算红色车…...

湖北咸宁农业三维扫描数字化农业3d打印制造应用-CASAIM中科广电

农业是人类衣食之源、生存之本&#xff0c;是一切生产的首要条件&#xff0c;CASAIM在农业三维扫描和3d打印应用上有丰富经验。 1.三维扫描技术在农业领域的应用 CASAIM三维扫描是集光学、机电和计算机技术于一体的高新无损检测技术&#xff0c;能够对实物的空间外形、结构乃…...

Jenkins的定时任务配置

jenkins配置定时任务位置(点击日程表的问好可查看语法配置) jenkins的定时任务的参数 # 定时任务参数(每个参数之间使用tab键或空格分隔)MINUTE HOUR DOM MONTH DOW 参数解释取值范围 MINUTE 分钟0-59HOUR小时0-23DOM一月的天数1-31MONTH月份1-12DOW 一周的天数0…...

THINKPHP 微联云投票系统源码独立版 + 支持刷礼物

THINKPHP 微联云投票系统源码独立版 支持刷礼物 nginxphp7.2以上 mysql5.6以上 简单测试后台基本没什么问题&#xff0c;暂时发现H5前端有bug,自行修复。...

Mongodb两种启动方法

一、命令行启动 1.修改存放数据库的位置 说明&#xff1a;E:\data\mongodb&#xff1b;我在E盘创建的文件夹mongodb mongod --dbpathE:\data\mongodb 2.成功启动 说明&#xff1a;默认端口27017&#xff0c;代表已经启动成功 &#xff0c;并在mongodb自动创建文件 二、配置项…...

Python:列表的浅拷贝与深拷贝

在python语言中&#xff0c;因为其面向对象的特性&#xff0c;在进行列表拷贝时可能会出现一些意想不到的结果&#xff0c;涉及到列表的浅拷贝和深拷贝相关问题&#xff0c;本文将对其进行总结。 首先我们来看以下代码。 my_list [1, 2, 3] your_list my_list your_list[0] …...

OnePlus Open可折叠手机:规格、价格、发布日期等详细信息汇总!

我们知道OnePlus可折叠手机即将问世,无论它是否被命名为OnePlus Open。我们迫不及待地想让它到来,为该公司再添一根弦,为最好的可折叠手机增添一个新的竞争对手。 OnePlus以前没有生产过任何可折叠产品,但它确实拥有合作伙伴公司Oppo的丰富知识,并可以向三星、摩托罗拉和…...

SQL 数据库

安装配置 【1】 MySQL安装配置教程&#xff08;超级详细、保姆级&#xff09; 【2】 MySQLNavicat安装配置教程&#xff08;超级详细、保姆级&#xff09; 学习资料 【戴师兄】SQL入门免费教程 刷题链接&#xff1a;https://share.mubu.com/doc/4BHMMbbvIMb 学习笔记&#xf…...

【算法系列篇】滑动窗口

文章目录 前言什么是滑动窗口1.长度最小的子数组1.1 题目要求1.2 做题思路 1.3 Java代码实现2.无重复字符的最长子串2.1 题目要求2.2 做题思路2.3 Java代码实现 3.最大连续1的个数 III3.1 题目要求3.2 做题思路3.3 Java代码实现 4.将x减到0的最小操作数4.1 题目要求4.2 做题思路…...

多维时序 | MATLAB实现BiTCN-BiGRU-Attention多变量时间序列预测

多维时序 | MATLAB实现SABO-CNN-GRU-Attention多变量时间序列预测 目录 多维时序 | MATLAB实现SABO-CNN-GRU-Attention多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 多维时序 | MATLAB实现BiTCN-BiGRU-Attention多变量时间序列预测。 模型描…...

Docker容器与虚拟化技术:Docker compose部署LNMP

目录 一、理论 1.LNMP架构 2.背景 3.Dockerfile部署LNMP 3.准备Nginx镜像 4.准备MySQL容器 5.准备PHP镜像 6.上传wordpress软件包 7.编写docker-compose.yml 8.构建与运行docker-compose 9.启动 wordpress 服务 10.浏览器访问 11.将运行中的 docker容器保存为 doc…...

高性能服务器Nodejs操作Mysql数据库

目录 1 Node 操作 mysql1.2 操作 mysql 数据库 2 Web 开发模式2.1 服务端渲染2.2 前后端分离2.3 如何选择 3 身份认证3.1 Session 认证机制3.2 JWT 认证机制 1 Node 操作 mysql 数据库和身份认证 配置 mysql 模块 安装 mysql 模块 npm install mysql建立连接 const mysql …...

ffmpeg将rtsp流转成mp4

命令行版本 ffmpeg -y -i "rtsp://你的rtsp地址" -vcodec copy -f mp4 d:/1.mp4中间的rtsp网址一定要加上双引号&#xff0c;避免出现url有特殊字符的问题 java代码版本 如果不支持tcp协议&#xff0c;去掉下面两个参数即可,加上这两个参数是因为ffmpeg默认使用ud…...

第十四天|层序遍历、226.翻转二叉树 (优先掌握递归)、101. 对称二叉树 (优先掌握递归)

层序遍历 题目链接&#xff1a;102. 二叉树的层序遍历 - 力扣&#xff08;LeetCode&#xff09; /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(n…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...

【Go语言基础【12】】指针:声明、取地址、解引用

文章目录 零、概述&#xff1a;指针 vs. 引用&#xff08;类比其他语言&#xff09;一、指针基础概念二、指针声明与初始化三、指针操作符1. &&#xff1a;取地址&#xff08;拿到内存地址&#xff09;2. *&#xff1a;解引用&#xff08;拿到值&#xff09; 四、空指针&am…...

Go 语言并发编程基础:无缓冲与有缓冲通道

在上一章节中&#xff0c;我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道&#xff0c;它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好&#xff0…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

C++.OpenGL (20/64)混合(Blending)

混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...