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

C语言标准库函数qsort( )——数据排序

  

大家好!我是保护小周ღ,本期为大家带来的是深度解剖C语言标准库函数 qsort(),qsort()函数他可以对任意类型的数据排序,博主会详细解释函数使用方法,以及使用快速排序的左右指针法模拟实现函数功能这样的排序确定不来学习一下吗???

 

8b354a7916f240d0bc7839822301ba90.gif#pic_center

目录

一、qsort()函数简介

二、qsort() 函数的参数

三、qsort() 函数的使用

3.1 对整型数据排序 

3.2 对结构体类型数据排序

 四、快速排模拟实现qsort()函数


一、qsort()函数简介

qsort() 函数是C语言标准库提供的排序函数,q==Quick,函数内部是以快速排序的思想实现的,那qsort() 函数的意义是什么呢?内部居然还使用别的排序的思想。因为常规排序是写死的,假如原先是对整型数据的排序,现在要对结构体类型的数据排序,则需要修改函数参数,函数内部数据也要相应的修改。而qsort()函数他可以对任意类型的数据排序,比如说,可以直接排整型数据,也可以排结构体类型的数据,甚至是字符串数据,通用性极强。这样的排序确定不来学习一下吗???


二、qsort() 函数的参数

很明显 qsort()函数具有4个参数,接下来博主来解剖一下这些参数代表着什么意思。

1.   void * base : 首先来了解一下什么是 void* ,这个是无具体类型的指针,void * 的指针是非常宽容的,可以接收任意类型的数据。常常用来临时存放数据,等到需要使用数据时,我们必须要强制类型转换成某一具体类型的数据,才能对数据进行操作。

对void *pa,接收了一个整型 a 的地址,我们对指针pa 进行强制类型转换(int*),再解引用 pa即可对变量a 进行操作。

 void *base 存的就是待排序数据的起始地址(不能直接访问)。

 这个参数是 qsort() 函数能够对任意数据排序的基础。 

2. size_t  num : 记录待排序数据元素个数。

3. size_t  size  : 记录待排序数据任意一个元素的所占的字节数(元素的大小)。

4. int  (*compar) (const  void*  , const  void* ) : 

这其实是一个函数类型的指针,可以用来存储函数的地址,然后也提前声明了函数的参数,返回值

返回值是 int 类型,参数部分是两个 void * 类型的接收。这个函数的作用是来比较两个参数的大小,然后返回比较果结,怎么比呢? 如果是整型数据使两个参数相减,返回结果。如果是字符串,我们可以使用   strcmp(“字符串”,“字符串”);strcmp 函数的返回值也是整型数据(这个是根据对应的场景,选择比较方式),即可得到相应的结果。

这第四个参数需要我们自己设计实现,函数的作用就是比较任意两个参数,返回一个整型数据,就可以利用这个数据来判断两个元素大小,所以这是个比较排序。


三、qsort() 函数的使用

qsort()函数包含在 stdlib.h库里,所以我在使用前需要申明一下。

3.1 对整型数据排序 

#include<stdio.h>
#include<stdlib.h>//头文件声明//判断两个元素的大小
int Compar(void const *p1,void const *p2)//无具体类型的指针接收数据,使用时强制类型转换。
{//两个整型数据相减,即可即可得到三种信息>,<,=return (*(int*)p1 - *(int*)p2) *(-1); //利用乘-1改变符号控制升序还是降序
}//打印
void Print(int *arr,int n)
{for (int i=0;i<n;++i){printf("%d ",arr[i]);}
}int main()
{int arr[] = { 8,6,4,2,3,7,1,2,3,10,9 };int len = sizeof(arr) / sizeof(arr[0]);//记录数组元素个数int size = sizeof(arr[0]);//记录某一个元素的大小所占的字节数//库函数qsort(arr, len, size, Compar);//第四个参数,直接传函数的地址,函数名代表函数的地址,由函数指针接收。//打印Print(arr, len);return 0;
}


3.2 对结构体类型数据排序

#include<stdio.h>
#include<stdlib.h>
#include<string.h>typedef struct Student//定义一个Student类型的结构体
{char name[12]; //姓名int age;       //年龄char StuID[8]; //学号
}Student;//typedef,重命名一下,简化。//比较任意两个元素的大小。
int CmpSort(const void* p1, const void * p2)
{//return ( ((Student*)p1)->age - ((Student*)p2)->age );//根据年龄来比return (strcmp(((Student*)p1)->name,((Student*)p2)->name));//按照姓名的首字母来比较
}//打印
void Print(Student* ps,int n)
{for (int i=0;i<n;++i){printf("%s %d %d\n",ps[i].name,ps[i].age,ps[i].StuID);}
}int main()
{Student student[3] = { {"张三",18,"21933321"},{"李四",20,"21933323"},{"王老五",19,"21933322"}};int len = sizeof(student) / sizeof(student[0]);//统计Student 类型,student数组的元素的个数int size = sizeof(student[0]);//统计某一个Student 元素所占的字节数。//库函数qsort(student,len,size,CmpSort);Print(student,len);//打印return 0;
}


 四、快速排模拟实现qsort()函数

好了经过以上三节内容的铺垫,相信大家应该对 qsort() 函数的用法,功能明白了,接下来我们就要来模拟实现函数内部。上文说到排序思想是用快速排序的思想。那博主今天就用快速排序——左右指针法来模拟实现挖坑法有一点复杂(下文解释)。

老铁如果对快速排序的几种排序思想还有什么不明白的可以学习博主的专栏。文章最后会贴。

什么是左右指针法?一张图带你搞定:

利用递归来继续分割区间,分割后继续单趟排,最后实现整体排序,排序结束。

算法逻辑弄明白了,现在还有一个问题,那就是函数内部,不知道我们要对什么类型的数据进行排序,我们虽然使用 void * 无指定类型的指针来接收数据,内部怎么根据数据的类型来进行强制类型转换呢?不转换无法处理数据。

大家回忆一下,我们qsort()函数是不是有四个参数,其中有一个参数就是 某一个元素所占的字节大小。size。

我们是不是可以将 void * 转换成 char * ,char* 的指针每一次只能访问一个字节的内容。

举个例子:

现在访问数据元素的问题解决了,那怎么交换数据元素的位置呢?

还是建立在访问元素的基础上,先找到需要交换的元素的位置,再根据 size 的大小一个字节一个字节的交换数据。

//交换数据
void Swap(char* base1, char* base2, int size)
{for (int i = 0; i < size; ++i)//按字节转换{char tmp = *base1;*base1 = *base2;*base2 = tmp;++base1;++base2;	}
}

这一趟下来,两个元素的就实现了交换。

完整版代码:

#include <stdio.h>
#include <stdlib.h>int Cmp_qsort(void const* p1, void const* p2)//用户输入,
{int size1 = (*(int*)p1 - *(int*)p2);return size1;
}//交换数据
void Swap(char* base1, char* base2, int size)
{for (int i = 0; i < size; ++i)//按字节转换{char tmp = *base1;*base1 = *base2;*base2 = tmp;++base1;++base2;	}
}//模拟实现
void _Quick_qsort(void const* base, int left, int right, int size, int(*Cmp_qsort)(void const* p1, void const* p2))
{if (left >= right){return;}int begin = left;int end = right;int key = begin;//记录坑位的下标、while (begin < end){while (begin < end && (Cmp_qsort((char*)base+ key*size, (char*)base + end * size) <= 0))--end;while (begin < end && (Cmp_qsort((char*)base+ key*size, (char*)base + begin * size) >= 0))++begin;Swap((char*)base +begin * size, (char*)base+end*size, size);}Swap((char*)base + begin * size, (char*)base + key * size, size);_Quick_qsort(base, left, begin - 1, size, Cmp_qsort);_Quick_qsort(base, begin + 1, right, size, Cmp_qsort);}//过渡一下
void Quick_qsort(void const* base, int len, int size,int(*Cmp_qsort)(void const *p1,void const *p2))
{_Quick_qsort(base, 0, len - 1, size, Cmp_qsort);//左右区间写入参数,
}//打印
void Print(int* a, int n)
{for (int i = 0; i < n; ++i){printf("%d ", a[i]);}
}//快排左右指针法
int main()
{int a[] = {6,1,2,10,7,9,9,3,4,5,10,8};int len = sizeof(a) / sizeof(a[0]);int size = sizeof(a[0]);Quick_qsort(a, len, size,Cmp_qsort);//快速排序模拟实现Print(a, len);//打印return 0;}

这个模拟是争对于顺序结构的数据,而链式结构要采用不同的办法。

不采用快排的挖坑发的原因是:我们需要一个类型大小的空间存坑值,这个时候我们只能根据size(一个元素所占的字节数)动态开辟一个char *的数组,一个字节一个字节的存储。如果光定义指针指向,那坑值指针,会随着指向地址的元素的变化而变化。 


至此,C语言的深度解剖 qsort() 函数,博主已经分享完了,希望对大家有所帮助,如有不妥之处欢迎批评指正。

 

本期收录于博主的专栏——数据排序,适用于编程初学者,感兴趣的朋友们可以订阅,查看其它“经典数据排序”。排序算法_保护小周ღ的博客

感谢每一个观看本篇文章的朋友,更多精彩敬请期待:保护小周ღ  *★,°*:.☆( ̄▽ ̄)/$:*.°★* 

文章存在借鉴,如有侵权请联系修改删除! ​​

相关文章:

C语言标准库函数qsort( )——数据排序

大家好&#xff01;我是保护小周ღ&#xff0c;本期为大家带来的是深度解剖C语言标准库函数 qsort()&#xff0c;qsort()函数他可以对任意类型的数据排序&#xff0c;博主会详细解释函数使用方法&#xff0c;以及使用快速排序的左右指针法模拟实现函数功能&#xff0c;这样的排…...

基础---nginx 启动不了,跟 Apache2 服务冲突

文章目录 查看 nginx 服务状态nginx 启动后 访问页面 127.0.0.1停止 nginx 服务&#xff0c;访问不了页面停止/启动 Apache2 服务&#xff0c;启动 Apache2 页面访问显示正确nginx 莫名启动不了卸载 Apache2 服务器 启动 nginx &#xff0c;但是总是不能实现反向代理&#xff0…...

如何利用百度SEO优化技巧将排到首页

拥有一个成功的网站对于企业和个人来说是至关重要的&#xff0c;在当今数字化的时代。在互联网上获得高流量和优质的访问者可能并不是一件容易的事情&#xff0c;然而。一个成功的SEO战略可以帮助你实现这一目标。需要一些特定的技巧和策略、但要在百度搜索引擎中获得较高排名。…...

CSS隐藏元素的方法 ( 5 种)

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…...

微信小程序(五十九)使用鉴权组件时原页面js自动加载解决方法(24/3/14)

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.使用覆盖函数的方法阻止原页面的自动执行方法 2.使用判断实现只有当未登录时才进行方法覆盖 源码&#xff1a; app.json {"pages": ["pages/index/index","pages/logs/logs"],…...

Git 学习笔记 三个区域、文件状态、分支、常用命令

Git 学习 GitGit概念VS Code中使用仓库&#xff08;repository&#xff09;示例 Git 使用时的三个区域示例 Git 文件状态示例 Git 暂存区示例 Git 回退版本删除文件忽略文件示例 分支分支的使用分支的合并与删除分支的合并冲突 Git常用命令Git远程仓库 (HTTP)步骤远程仓库 克隆…...

OrangePiLinux连接小米手机使用adb显示“List of devices attached”的问题解决

参考文章adb连接不上手机&#xff0c;提示“List of devices attached” - 简书 (jianshu.com) adb解决报错error: no devices/emulators found error: cannot connect to daemon_adb.exe: no devices/emulators found-CSDN博客 error: no devices/emulators found解决办法-C…...

【Jenkins】data stream error|Error cloning remote repo ‘origin‘ 错误解决【亲测有效】

错误构建日志 17:39:09 ERROR: Error cloning remote repo origin 17:39:09 hudson.plugins.git.GitException: Command "git fetch --tags --progress http://domain/xxx.git refs/heads/*:refs/remotes/origin/*" returned status code 128: 17:39:09 stdout: 17…...

3.1_9 基本分段存储管理

文章目录 3.1_9 基本分段存储管理&#xff08;一&#xff09;分段&#xff08;二&#xff09;段表&#xff08;三&#xff09;地址变换&#xff08;四&#xff09;分段、分页管理的对比 总结 3.1_9 基本分段存储管理 &#xff08;一&#xff09;分段 进程的地址空间&#xff1a…...

基于SpringBoot+Druid实现多数据源:baomidou多数据源

前言 本博客姊妹篇 基于SpringBootDruid实现多数据源&#xff1a;原生注解式基于SpringBootDruid实现多数据源&#xff1a;注解编程式基于SpringBootDruid实现多数据源&#xff1a;baomidou多数据源 一、功能描述 支持 数据源分组 &#xff0c;适用于多种场景 纯粹多库 读写…...

Redis开发规范与性能优化(二)

开发规范与性能优化 3.客户端使用 1.【推荐】避免多个应用使用一个Redis示例 正例:不相干的业务拆分&#xff0c;公共数据库做服务化 2.【推荐】使用带有连接池的数据库&#xff0c;可以有效控制链接&#xff0c;同时提高效率&#xff0c;标准使用方式如代码所示 public c…...

我们是否生活在一个超大型生物的大脑之中?——对多元宇宙观与生命存在形式的哲学探讨

随着科技和哲学思辨的深入&#xff0c;关于人类所处宇宙的本质及我们自身存在的真实性的讨论越发引人入胜。其中一种颇具科幻色彩的观点认为&#xff0c;我们可能生活在某个巨大生物的大脑之中&#xff0c;所有的物理规律、自然现象以及我们的感知体验&#xff0c;都可能是这个…...

【Python数据结构与判断7/7】数据结构小结

目录 序言 整体回忆 定义方式 访问元素 访问单个元素 访问多个与元素 修改元素 添加元素 列表里添加元素 字典里添加元素 删除元素 in运算符 实战案例 总结 序言 今天将对前面学过的三种数据结构&#xff1a;元组&#xff08;tuple&#xff09;、列表&#xff08;…...

探讨:MySQL和PostgreSQL谁更火

一、有人说PostgreSQL比MySQL火&#x1f525; PostgreSQL相比于MySQL越来越受欢迎的原因可以从以下几个方面来阐述&#xff1a; 许可协议灵活性&#xff1a; PostgreSQL采用的是较为宽松的BSD许可证&#xff0c;允许企业在开源的基础上自由使用、修改和分发&#xff0c;而无需…...

hbase和es的选取 hbase与es结合

hbase和es的选取 hbase与es结合 背景介绍 HBase与ElasticSearch是现代应用在处理海量数据的技术架构会经常被使用的两款产品&#xff0c;其中HBase是一个分布式KV系统&#xff0c;具有灵活Schema、水平扩展、低成本、高并发的优势&#xff0c;但在复杂查询、分析能力方面相对…...

GoLang:云原生时代致力于构建高性能服务器的后端语言

Go语言的介绍 概念 Golang&#xff08;也被称为Go&#xff09;是一种编程语言&#xff0c;由Google于2007年开始设计和开发&#xff0c;并于2009年首次公开发布。Golang是一种静态类型、编译型的语言&#xff0c;旨在提供高效和可靠的软件开发体验。它具有简洁的语法、高效的编…...

高频面试必备(Java研发岗),一线互联网架构师设计思想解读开源框架

BeanFactory 和 ApplicationContext 有什么区别&#xff1f; 如何用基于 XML 配置的方式配置 Spring&#xff1f; 如何用基于 Java 配置的方式配置 Spring&#xff1f; 请解释 Spring Bean 的生命周期&#xff1f; Tomcat Tomcat 的缺省端口是多少&#xff0c;怎么修改&…...

React——react 的基本使用

前提&#xff1a;安装全局的脚手架&#xff0c;通过create-creat-app 项目名&#xff0c;我们创建好一个新项目&#xff0c;cd进去&#xff0c;通过npm start去运行该项目 注意&#xff1a;简单看下demo的配置&#xff0c;在根目录我们可以看到&#xff0c;没有任何webpack的…...

Unity资源热更新----AssetBundle

13.1 资源热更新——AssetBundle1-1_哔哩哔哩_bilibili Resources 性能消耗较大 Resources文件夹大小不能超过2个G 获取AssetBundle中的资源 打包流程 选择图片后点击 创建文件夹&#xff0c;Editor优先编译 打包文件夹位置 using UnityEditor; using UnityEngine; public cla…...

bootstrap企业网站前端模板

介绍 企业网站前端模板 软件架构 前端所用技术html/css/js/jquery 前端框架bootstrap 安装教程 浏览器本地路径访问发布到服务器比如&#xff08;tomcat/nginx等&#xff09;云服务器/虚拟机 网站效果图 网站预览 点击预览 源码地址 https://gitee.com/taisan/company…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中&#xff0c;选择 环境 -> 常规 &#xff0c;将其中的颜色主题改成深色 点击确定&#xff0c;更改完成...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

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

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

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

Swagger和OpenApi的前世今生

Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章&#xff0c;二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑&#xff1a; &#x1f504; 一、起源与初创期&#xff1a;Swagger的诞生&#xff08;2010-2014&#xff09; 核心…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...