【C语言】qsort函数的使用和模拟实现

本篇文章我们来了解一下回C语言中qsort函数的使用方法和模拟实现。这是一个通用性很强而且非常方便的库函数,通过这篇文章希望能让你了解sort函数。

目录

一、qsort的介绍:

二、qsort函数的使用

1.qsort排序整形

2.qsort排序字符串 

3.qsort排序结构体中的整形

4.qsort排序结构体中的字符串

三、qsort的实现


一、qsort的介绍:

二、qsort函数的使用

qsort的使用需要引用头文件<stdlib.h>或<search.h>

然后我们来看qsort需要的参数,一共四个参数,具体要求如下:

void* base——待排序目标的地址

size_t  num——表示的是待排序目标需要排序的个数,可以是整个要排序的目标,也可以是目标中的一段部分

size_t——width,表示待排序数据的宽度

④表示一个函数指针,需要我们传入一个自定义的比较函数,用来比较两个数据中的大小关系。

1.qsort排序整形

代码如下:

//比较函数:
int compare(const void* r1, const void* r2)
{return (*(int*)r1 - *(int*)r2);
}int main ()
{int  arr[10] = { 1,3,5,7,6,2,0,8,9,4 };qsort(arr, sizeof(arr)/sizeof(arr[0]), sizeof(int), compare);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}printf("\n");return 0;
}

这里有几个需要注意的点:

①compare函数,这个函数可以传入qsort函数中,让qsort函数知道两个数据间的大小关系,这个函数是需要我们自己创建的,我们只要书写了比较函数,我们可以比较绝大多数数据类型。

②compare函数中的参数我们必须写成const void*类型,因为void*型可以接受任意类型的数据,我们只需要传入width就可以控制操作的字节数,不会像int*、char*型将类型定死,这样就会导致qsort失去了通用性

③qsort中一个参数是一种函数指针类型,所以我们将函数的函数名传入就行了,因为函数名就表示函数地址。

④两个元素间的大小关系,如果是升序,即r1-r2,如果是降序,就是r2-r1。qsort默认的排序方式是升序,即r1-r2>0的情况

qsort函数的通用性关键就在于我们自己定义的比较函数,接下来我们写写看比较字符串、结构体里的整形/字符串如何使用qsort实现,以及对应的compare如何书写。

2.qsort排序字符串 

qsort函数最关键的其实就是我们书写的比较函数。我们来分析一下比较字符串函数的书写。

首先,这里我将arr1、arr2、arr3放入arr_name数组中,arr1、arr2、arr3表示首元素的地址,而arr_name也表示首元素的地址,所以arr_name是一个二级指针,我们将一些常规参数书写后开始书写comp_name函数,固定的函数参数const void*型。

其次,我们比较字符串的大小不能直接使用加减乘除,我们要使用strcmp函数来比较字符串。

然后,strcmp函数在比较完之后会返回一个值来表示两个字符串的大小关系,共有三种情况,str1>str2,会返回一个大于0的值;str1<str2,返回一个小于0的值;str1==str2,strcmp会返回0,所以我们直接return strcmp返回的值既可。

最后,我们开始将r1指针进行强制类型转化,因为arr_name是一个二级指针,所以我们要先将r1、r2转化为char**型的二级指针,而strcmp函数比较的是一级指针,所以我们再对此指针解引用一次,就可以将对应arr1、arr2中字符串的首地址传入strcmp函数被正常调用。

代码如下:

//使用strcmp函数比较字符串
int comp_name(const void* r1, const void* r2)
{return strcmp( *((char**)r1), *((char**)r2));
}
int main()
{char arr1[20] = "zhangsan";char arr2[20] = "lisi";char arr3[20] = "wangwu";char* arr_name[3] = { arr1,arr2,arr3 };char** p = arr_name;qsort(arr_name, sizeof(arr_name) / sizeof(arr_name[0]), sizeof(arr_name[0]), comp_name);printf("%s\n", arr_name[0]);  //李四第一printf("%s\n", arr_name[1]);  //王五第二printf("%s\n",arr_name[2]);   //张三第三
}

3.qsort排序结构体中的整形

注意事项:

1.因为我传入的是结构体数组,所以我要将r1、r2强制类型转换为结构体指针,并且要保证结构体类型相同,都是struct stu类型的。

2.因为r1、r2是结构体指针了,我就可以直接使用r1来指向结构体中的数据,从而来比较结构体数据中的大小。

//比较函数:
int com_struct_score(const void* r1, const void* r2)
{return ((struct stu*)r1)->score - ((struct stu*)r1)->score;
}int main ()
{//定义一个结构体数组struct stu student_arr[3] = { { 210603,"wangwu",90 },{ 210602,"lisi",70 } ,{ 210601,"zhangsan",80 } };//排序前printf("排序前:\n%s %d\n", student_arr->name, student_arr->score);printf("%s %d\n", (student_arr + 1)->name, (student_arr + 1)->score);printf("%s %d\n", (student_arr + 2)->name, (student_arr + 2)->score);//排序qsort(student_arr, sizeof(student_arr) / sizeof(student_arr[0]), sizeof(student_arr[0]), com_struct_score);//排序完成printf("\n\n排序后:\n%s %d\n", student_arr->name, student_arr->score);printf("%s %d\n", (student_arr + 1)->name, (student_arr + 1)->score);printf("%s %d\n", (student_arr + 2)->name, (student_arr + 2)->score);printf("\n");printf("\n");return 0;
}

4.qsort排序结构体中的字符串

注意事项:

1.我传入的是结构体指针数组,因为是数组,而且每个元素是结构体指针类型,所以我要将r1转化为结构体二级指针。

2.因为比较的是name,所以我们要再次使用strcmp函数来比较字符串大小。

3.特别注意:我们要知道()的优先级大于成员选择操作符(->),而成员选择操作符(->)的优先级又大于*号,所以我们要使用括号来保证优先级顺序:①r1先于(struct**)结合,②(struct**)r1与*号结合,表示从student_arrx数组中拿出了student1,所以r1现在指向student1,所以我们再使用成员选择操作符(->)就可以访问到这个结构体中的字符串了!但是,上面说了,成员选择操作符(->)的优先级大于*号,所以我们要用括号括起来(*(struct**)r1),再使用->。

 代码如下:

//比较函数:
int com_structx1_name(const void* r1, const void* r2)
{return  strcmp((*((struct stu**)r1))->name, (*((struct stu**)r2))->name);
}int main()
{struct stu student1 = { 210603,"wangwu",80 };struct stu student2 = { 210602,"lisi",99 };struct stu student3 = { 210601,"zhangsan",100 };struct stu* student_arrx[3] = { &student1,&student2,&student3 };//排序前printf("排序前:\n%s %d\n", student_arrx[0]->name, student_arrx[0]->score);printf("%s %d\n", student_arrx[1]->name, student_arrx[1]->score);printf("%s %d\n", student_arrx[2]->name, student_arrx[2]->score);//开始排序qsort(student_arrx, sizeof(student_arrx) / sizeof(student_arrx[0]), sizeof(student_arrx[0]), com_structx1_name);//排序后printf("\n\n排序后:\n%s %d\n", student_arrx[0]->name, student_arrx[0]->score);printf("%s %d\n", student_arrx[1]->name, student_arrx[1]->score);printf("%s %d\n", student_arrx[2]->name, student_arrx[2]->score);//李四第一//王五第二//张三第三return 0;
}

三、qsort的实现

接下来我们来自己模拟实现一个qsort函数,因为我们这个实现qsort函数主要是为了实现qsort函数的通用性,所以我们可以用冒泡排序来实现qsort函数的通用性,(大家也可以使用快排算法再来模拟实现qsort函数)。

实现结果:

代码如下(排序的是上一个例子):

#include <stdio.h>
#include <string.h>
//定义结构体
typedef struct student
{char name[20];int score;
}student;
//自定义比较函数  使用strcmp函数比较字符串大小
int  compare_student(const void* r1, const void* r2)
{return strcmp((*((student**)r1))->name, (*((student**)r2))->name);
}
//交换函数,使用char*指针一个字节一个字节交换
void swap(char*r1,char* r2, size_t width)
{size_t  i = 0;for (i = 0; i < width; i++){char temp = 0;temp = *r1;*r1 = *r2;*r2 = temp;r1++;r2++;}
}
//自定义qsort函数的实现
void My_bubble_qsort(void* base, size_t num, size_t width, int (*compare)(const void*r1 ,const void*r2 ))
{size_t i = 0;size_t j = 0;for (i = 0; i < num-1; i++){for (j = 0; j < num - 1 - i; j++){if (compare((char*)base + j * width, (char*)base + (j + 1) * width) > 0){swap((char*)base + j * width, (char*)base + (j + 1) * width, width);}}}
}
int main()
{student wangwu = { "wangwu",75 };student lisi = { "lisi",94 };student zhangsan = { "zhangsan",60 };student* arr_student[3] = { &wangwu,&lisi,&zhangsan };//定义结构体指针数组int i = 0;printf("排序前:\n");for (i = 0; i < 3; i++){printf("%s,%d\n", arr_student[i]->name, arr_student[i]->score);}My_bubble_qsort(arr_student, sizeof(arr_student) / sizeof(arr_student[0]),sizeof(arr_student[0]),compare_student );printf("\n排序后:\n");for (i = 0; i < 3; i++){printf("%s,%d\n", arr_student[i]->name, arr_student[i]->score);}return 0;
}

My_bubble_qsort实现讲解:

1.设置参数:我们将base设置为void*型,num、width设置为size_t(无符号整形),一个返回值为int型,两个参数为void*型的函数指针。

2.在判断条件中,判断是否进行两个数据间的交换,我们设置在只有compare函数返回大于0才进行。

3.传到compare函数中参数设置,这里我们将要比较的类型先转化为char*型,指向一个字节,因为char*型指针指向一个字节,我们不知道传入的类型大小是多少,所以我们可以先设置为char*型指针指向传入的元素我们可以再加上宽度 ,这就可以让char*指针指向下一个数据,如果我们再将(width*j),这就可以传入这一串数据中的第j个元素。这样第一个参数就设置好了,因为冒泡排序是两个相邻的元素比较,所以第二个元素我们只用再j的基础上+1就可以表示下一个元素了。

4.交换函数(swap),当我们发现compare函数的返回值大于1时,我们就要开始进行交换。先将要交换的两个元素以char*型的形式传入,再将width传入swap函数。这时使用char*型指针的优势就体现了出来,因为char*型指针只改变一个字节,所以我们再将width传入,使用char*一个字节一个字节进行交换,直到i<width,这样就可以将两个数据数据交换完成,适用于所有类型的交换。

qsort是一个通用性很强的函数,可以排序绝大多数的数据结构,但是关于qsort的使用,仍需要我们大量练习才可以熟练掌握。

好了,本篇文章就到这结束了,感觉不错的朋友门可以留个赞噢~

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

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

相关文章

C语言之——快速排序qsort库函数的讲解

qsort函数C语言编译器函数库自带的排序函数&#xff0c;也叫快速排序函数。之前我写过一篇关于冒泡排序的代码讲解&#xff0c;大家感兴趣的话可以先看一看我对于冒泡排序的讲解。 相比较于冒泡排序&#xff0c;快速排序可以用更加快捷的速度去排列升降序&#xff0c;它的时间复…

C语言qsort函数使用方法大全

文章目录 一、qsort函数简介二、qsort函数常用实例1.比较整型数组2.比较char数组3.比较double数组4.比较字符串4.1按首字母排序4.2按长度排序4,3按字典顺序 5.结构体排序5.1 多级排序 三、qsort深度剖析 一、qsort函数简介 排序方法有很多种&#xff1a;选择排序&#xff0c;冒…

C语言-qsort函数详解

目录 一.qsort函数是什么 二.使用qsort排序-以升序为例 关于void*型指针&#xff1a; 1.整形数组排序 2.字符数组排序 3.字符指针数组排序 4.结构体数组排序 5.浮点型数组排序 三.使用冒泡排序思想模拟实现qsort函数 1.什么是冒泡排序&#xff1a; 2.冒泡排序代码 3. …

C语言qsort()函数的使用(详解)

目录 1.参数含义 1.首元素地址base 2.元素个数num 3.元素大小size 4.自定义比较函数compar 2.使用方式 1.头文件 2.compar的实现 3.整体代码 qsort&#xff08;&#xff09;函数&#xff08;quick sort&#xff09;是八大排序算法中的快速排序&#xff0c;能够排序任意…

虚幻4地形怎么增加层_虚幻周报20200407 | 在家也要好好工作呀~

官方知乎号&#xff1a;虚幻引擎 搜集日期&#xff1a;20200330-20200405 整理编辑&#xff1a; 大钊&#xff0c;小辉辉&#xff0c;马古斯&#xff0c;小帅帅 声明&#xff1a;文档搜集来自网上&#xff0c;难免遗漏&#xff0c;请联系我们投稿和添加关注。该文档版权归整理…

2020年笔记本电脑选购指南

**本文首发微信公众号陈蛋蛋碎碎念&#xff0c;获取更多软件、教程、模板资源&#xff0c;请关注公众号。 最近在群里有小伙伴问关于选购电脑的事&#xff0c;毕竟开学季又要到了。刚好蛋蛋现在又在3C公司工作&#xff0c;所以平时也需要了解这方面的知识&#xff0c;于是就准…

[转]Warzone 2100(战争地带2100)

发行公司&#xff1a;Eidos Interactive 开发公司&#xff1a;Pumpkin Studios 游戏类型&#xff1a;即时战略 游戏语言&#xff1a;英文 发行日期&#xff1a;1999 年4月 系统操作&#xff1a;Win95以上 伴随着这部来自英国开发公司Pumpkin Studios的作品&#xff0c;1999年…

显卡优化软件测试面试,是吹嘘还是真有用?NV游戏优化软件测试

1前言&#xff1a;NVIDIA游戏优化软件试用 英伟达真实热衷为用户提供出色的游戏方案&#xff0c;日前发布了一款GeForce Experience的新软件&#xff0c;本质上是一个基于云端的服务&#xff0c;旨在分析你的硬件并自动调整显示分辨率和游戏设置&#xff0c;以提供更好更优化的…

【转】为什么中国不会有3A游戏

编&#xff1a;王妙一&#xff0c;游戏开发者&#xff0c;代表作《WILL&#xff1a;美好世界》&#xff0c;曾获第二届PlayStation开发者大赛冠军。王妙一大学时就读于清华软件学院图形研究所&#xff0c;本文将从游戏图形技术的发展变迁开始&#xff0c;谈谈3A游戏在现今&…

FPS游戏

FPS 求助编辑百科名片 FPS FPS是第一人称射击类游戏的简称&#xff08;游戏专有名词&#xff09;。 FPS&#xff08;First-Person Shooter Game&#xff09;&#xff1a;第一人称射击游戏 严格来说FPS属于ACT类游戏的一个分支&#xff0c;但和RTS类游戏一样&#xff0c;由于其在…

Centos6.5环境Nginx 1.16.1升级到1.24.0版本

一、背景 2023年4月11日&#xff0c;官方发布了Nginx最新稳定版&#xff0c;版本号为 1.24.0。该版本是基于1.23.x&#xff08;1.23.0 - 1.23.4&#xff09;开发版的Bug修复&#xff0c;以及一些新特性的加入&#xff0c;而形成的稳定版。安全部门扫描后&#xff0c;发现现场不…

C++11 -- 包装器

文章目录 function包装器function包装器的概念function的运用function实例化使用function解决逆波兰表达式 bind包装器bind包装器相关介绍bind绑定函数固定参数 function包装器 function包装器的概念 function包装器,也叫做适配器,它的本质是一个类模板. 例如: 1 template&l…

chatgpt赋能python:Python中撤销的快捷键

Python中撤销的快捷键 在编程中&#xff0c;我们经常需要进行调试&#xff0c;不可避免地会出现一些错误&#xff0c;这时候撤销 (Undo) 功能就显得尤为重要。在 Python 中&#xff0c;我们可以使用一些快捷键来快速撤销&#xff0c;本文将会介绍这些快捷键的使用以及使用它们…

chatgpt赋能python:Python中的构造函数

Python 中的构造函数 Python 是一门广泛应用于各种应用领域的高级编程语言&#xff0c;它支持不同的编程范式&#xff0c;包括面向对象编程。在面向对象编程中&#xff0c;构造函数是一个重要的概念。本文将介绍 Python 中的构造函数&#xff0c;并介绍如何使用它们来创建对象…

淘宝店铺老店标识怎么显示 怎么淘宝老店标识申请

我们在很多时候都喜欢去一个淘宝开的时间比较长的店铺去购买商品&#xff0c;因为这样的店铺可能在信誉度这一块会更加能够让人信服&#xff0c;因为一个店铺能开这么久&#xff0c;肯定还是证明这个店铺拥有一定的实力。淘宝店铺老店标识怎么显示 怎么淘宝老店标识申请 在回答…

22-0001 淘宝店铺搜索界面

淘宝店铺搜索界面 1.元素2.过程2.1 搜索界面的网页源码2.2 通过Chrome控制台获取sellerid2.3 搜索链接2.4 控制台 3.总结 1.元素 获取店铺搜索界面每个店铺的’sellerid’ 备注&#xff1a;通过sellerid可以在下面链接中获取买家秀的图片&#xff0c;也可以使用相关软件进行下…

淘宝开店指南——店铺设置篇

目录 店铺基本设置店铺装修手机店铺装修PC 店铺装修 保证金管理客服&#xff08;子账号&#xff09;管理创建子账号修改子账号权限 店铺基本设置 通过千牛主账号工作台左侧点击【店铺】->选择【店铺信息进入】。 设置链接&#xff1a;点击访问 可设置内容&#xff1a; 个…

淘宝/天猫API:seller_info-获得淘宝店铺详情

万邦淘宝/天猫获得淘宝店铺详情 API 返回值说明 seller_info-获得淘宝店铺详情 onebound.taobao.seller_info 公共参数 请求地址: https://console.open.onebound.cn/console/?ipony 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;…

SpringCloud Alibaba Seata 工作机制

SpringCloud Alibaba Seata Seata 工作机制 说明 之所以放在后面说工作机制是因为如果一开始就说的话理解困难 所以我们有了前面的列子和说明我们在结合本节内容会收获的多理解相对容易点 分布式事务过程分析 Seata 分布式事务处理过程-ID三组件模型 debug 梳理: 术语 先…

ShardingSphere笔记(三):自定义分片算法 — 按月分表·真·自动建表

ShardingSphere笔记&#xff08;二&#xff09;&#xff1a;自定义分片算法 — 按月分表真自动建表 文章目录 ShardingSphere笔记&#xff08;二&#xff09;&#xff1a;自定义分片算法 — 按月分表真自动建表一、 前言二、 Springboot 的动态数据库三、 实现我们自己的动态数…