当前位置: 首页 > 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…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

C++:std::is_convertible

C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

【力扣数据库知识手册笔记】索引

索引 索引的优缺点 优点1. 通过创建唯一性索引&#xff0c;可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度&#xff08;创建索引的主要原因&#xff09;。3. 可以加速表和表之间的连接&#xff0c;实现数据的参考完整性。4. 可以在查询过程中&#xff0c;…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)

可以使用Sqliteviz这个网站免费编写sql语句&#xff0c;它能够让用户直接在浏览器内练习SQL的语法&#xff0c;不需要安装任何软件。 链接如下&#xff1a; sqliteviz 注意&#xff1a; 在转写SQL语法时&#xff0c;关键字之间有一个特定的顺序&#xff0c;这个顺序会影响到…...

Linux-07 ubuntu 的 chrome 启动不了

文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了&#xff0c;报错如下四、启动不了&#xff0c;解决如下 总结 问题原因 在应用中可以看到chrome&#xff0c;但是打不开(说明&#xff1a;原来的ubuntu系统出问题了&#xff0c;这个是备用的硬盘&a…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

Redis:现代应用开发的高效内存数据存储利器

一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发&#xff0c;其初衷是为了满足他自己的一个项目需求&#xff0c;即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源&#xff0c;Redis凭借其简单易用、…...

提升移动端网页调试效率:WebDebugX 与常见工具组合实践

在日常移动端开发中&#xff0c;网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时&#xff0c;开发者迫切需要一套高效、可靠且跨平台的调试方案。过去&#xff0c;我们或多或少使用过 Chrome DevTools、Remote Debug…...