qsort函数的理解和使用
目录
qsort函数
cmp函数的自定义
主函数
排序int类型代码
排序结构体
排序结构体的总代码(供读者测试)
qsort函数
qsort函数是<stdlib.h>库函数中的,基于快速排序算法的函数,可以对任意类型的数据进行排序
void qsort (void* base,//待排序数组的起始位置szie_t num,//数组的元素个数size_t width,//一个元素的字节大小int(*cmp)(const void* el,const void* e2)//函数指针//cmp:比较函数,要求qsort函数的使用者自定义一个比较函数//如果排序的是结构体数据,就不方便直接使用<>比较了//使用者根据实际情况,提供一个函数//该函数的返回值需要:e1 < e2,返回负数,否则是整数或者是0(升序)//该函数的返回值需要:e1 > e2,返回负数,否则是整数或者是0(降序)//e1,e2是待比较的两个元素的地址);
该函数有四个参数:
void* base : 这是待排序数组的起始位置,我们肯定必须要先找到那个数组才能进行排序啊
size_t num : 需要我们传入该数组的元素个数
size_t width : 需要我们传入一个元素的字节大小,具体为啥需要这个数据,我们后面自然就懂了
int(*cmp)(const void* el,const void* e2) : 这个参数可能有一点难以理解,我们可以知道,这其实是一个函数指针,指向一个参数是const void* el,const void* e2,返回值是 int 的函数。这个函数需要我们使用者自己去创建,注意,参数和返回类型必须严格按照它给的那样写。至于这个函数里面写什么,请看下文。
cmp函数的自定义
cmp,顾名思义,是compare(比较),就是一个比较函数。那么为什么qsort函数不自己写,而是需要我们使用者自己写呢?因为在设计qsort函数的时候,我们并不能知道使用者比较的是什么类型的数据,我们没有办法写一个函数来比较所有可能的类型的数据,比如,如果我们排序的是结构体数据,我们必须告诉qsort函数应该使用什么样的规则来比较。
所以这个函数的内容就是,比较我们需要比较的数据类型,如果e1大于e2,那就返回一个大于零的数,反之,就返回一个小于零的数(显然,这是针对于升序排序的,如果你想要进行降序的排序,就要将结果的正负号反过来)。
int cmp_int(const void* e1,const void* e2)
//void类型的指针是不确定类型的指针,是不能直接解引用的
//它更像是一个垃圾桶,用来接受任意类型的指针,但是不能(p + 1)
//因为他不知道它步长是多少
{if (*(int*)e1 > *(int*)e2){return 1;}else if (*(int*)e1 == *(int*)e2){return 0;}elsereturn -1;
}
但是这样写着太复杂了,我们不妨换个方式:
int cmp_int(const void* e1,const void* e2)
{return (*(int*)e1 - *(int*)e2) ;
}
即两个数相减,如果第一个数大于第二个数,那他们的差肯定就是负数了呗。
ps.我们习惯把这个函数命名为:cmp_数据类型,这样大大提高了程序的可读性。
写完这个函数,我们的准备工作就做好了
主函数
我们飞速地写出测试函数的主函数:
我们随便创建了一个乱序的数组,然后传入相应的参数到qsort函数中,并将最后的结果打印出来。
int main(void)
{int arr[] = {2,1,4,5,7,5,8,9};int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr,sz,sizeof(arr[0]),cmp_int);for(int i = 0; i < sz; i++){printf("%d ",arr[i]);}return 0;
}
排序int类型代码
int cmp_int(const void* e1, const void* e2)
{return (*(int*)e1 - *(int*)e2);
}int main(void)
{int arr[] = { 2,1,4,5,7,5,8,9 };int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_int);for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;
}
这其实就已经实现我们的排序了,不过我们为了深入掌握这个函数,不妨多排序几组不同类型的数据
排序结构体
首先,我们要创建一个结构体:
struct Stu
{char name[20];int age;double score;
};
然后初始化结构体。并写出qsort函数,这里我们为了更透彻理解这个函数,我们排序了两种,一种是结构体中的字符串排序(至于字符串怎么比较大小,请参考你查英语字典的顺序),和结构体中的整型的大小
int main(void)
{struct Stu arr[3] = {{"zhangsan",20,55.5},{"lisi",30,88.0},{"wangwu",50,90.0}};int sz = sizeof(arr)/sizeof(arr[0]);qsort(arr,sz,sizeof(arr[0]),cmp_stu_by_age);qsort(arr,sz,sizeof(arr[0]),cmp_stu_by_name);return 0;
}
接着,我们就需要自定义我们的cmp函数了,注意定义的时候参数一定要按照规定的来,最好不要自己自由发挥哈(为了方便大家观看,我特地写成了这种代码风格,希望大家别介意)
int cmp_stu_by_age(const void* e1,const void* e2)
{return (((struct Stu*)e1)->age - ((struct Stu*)e2)->age);
}int cmp_stu_by_name(const void* e1,const void* e2)
{return strcmp(((struct Stu*)e1)->name , ((struct Stu*)e2)->name);
}
因为void*指针,电脑不知道他的步长,怎么可能知道每次解引用要访问后面多大的空间呢,所以在这里我们必须要进行强制类型转换,转换为结构体指针变量,然后用操作符访问age和name,之后比较大小。
当然,我上文提到过,用这种逻辑我们最后得到的是一个升序的数组,如果我们想要得到一个降序的数组怎么办呢?
我们拿age的排序举个例子吧:
//升序排序
int cmp_stu_by_age(const void* e1,const void* e2)
{return (((struct Stu*)e1)->age - ((struct Stu*)e2)->age);
}
//降序排列:
int cmp_stu_by_age2(const void* e1,const void* e2)
{return (((struct Stu*)e2)->age - ((struct Stu*)e1)->age);
}
不难发现,只需要将返回值取个相反数(或者把减数和被减数交换位置,最终的效果都是一样的)。这样我们便能将一个数组进行降序的排序了,这便是qsort的强大之处,它允许你排序任何数据类型,也允许你自己设置排序的顺序。
最后,运行即可
排序结构体的总代码(供读者测试)
//创建一个结构体类型
struct Stu
{char name[20];int age;double score;
};
//升序排序年龄
int cmp_stu_by_age1(const void* e1,const void* e2)
{return (((struct Stu*)e1)->age - ((struct Stu*)e2)->age);
}
//降序排列年龄:
int cmp_stu_by_age2(const void* e1,const void* e2)
{return (((struct Stu*)e2)->age - ((struct Stu*)e1)->age);
}
//升序排序名字
int cmp_stu_by_name(const void* e1,const void* e2)
{return strcmp(((struct Stu*)e1)->name , ((struct Stu*)e2)->name);
}
int main(void)
{struct Stu arr[3] = {{"zhangsan",20,55.5},{"lisi",30,88.0},{"wangwu",50,90.0}};int sz = sizeof(arr)/sizeof(arr[0]);qsort(arr,sz,sizeof(arr[0]),cmp_stu_by_age1);qsort(arr,sz,sizeof(arr[0]),cmp_stu_by_age2);qsort(arr,sz,sizeof(arr[0]),cmp_stu_by_name);return 0;
}
qsort函数的理解和使用相关推荐
- C中的qsort函数和C++中的sort函数的理解与使用
一.qsort()函数 原型:_CRTIMP void __cdecl qsort (void*, size_t, size_t,int (*)(const void*, const void*)); ...
- 【C进阶】qsort函数详解
⭐博客主页:️CS semi主页 ⭐欢迎关注:点赞收藏+留言 ⭐系列专栏:C语言进阶 ⭐代码仓库:C Advanced 家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们 ...
- 【C语言】—— qsort()函数的使用
要学习qsort()函数首先要先了解回调函数 文章目录 一.回调函数 二.qsort函数是什么? 三.用qsort函数排序 1. 整型 2. 结构体 3. 字符型 4. double型 四.具体样例 ...
- 【qsort函数实现】
前言: 首先在进行讲解之前,我们先进行对函数的一些相关介绍,方便大家更好的理解它. 目录 函数介绍 函数实现 函数介绍 第一步: 我们可以先查询知道函数的使用方法: void qsort (void* ...
- qsort函数的使用
今天在刷题时,题目: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. ...
- 实验课题——最全手机通信录实现版本(【含注释】848行代码)!!!(包括模糊查询、分类查找、模拟拨号、qsort函数实现排序、文件存储、防误触等功能)
目录 简介: 基本要求: 代码的实现: 1.Contact.h 2.test.c 3.Cantact.c 运行效果图: 部分复杂函数流程图 前两周是本人的实验周,抽到的课题是"手机通信录的实 ...
- qsort函数详细讲解,各种用法,妙用
众所周知,在C++中有STL库可以用来进行排序,而对于新手来说很少知道C语言竟然也有自己的排序函数. qsort(基本快速排序的方法,每次把数组分成两部分和中间的一个划分值,而对于有多个重复值的数组来 ...
- 趣谈C语言之qsort函数
在学习c语言的时候,我们接触到了冒泡排序,利用冒泡排序我们可以快速的对一个数组进行大小的比较,可是大家有没有想过一个问题,有没有一种排序方式可以排序任何类型的元素类型的呢?答案是有的,它是qsort函 ...
- C语言进阶 -- 回调函数以及qsort函数的使用
一.回调函数 1.1.什么是回调函数??? 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数.回调 ...
最新文章
- 二维费用 hdu 2159 FATE(完全背包)HDU OJ 4501 小明系列故事——买年货【DP】
- LSB最低有效位和MSB最高有效位
- linq to sql 多条件组合查询
- 百度地图mysql打点_关于百度地图连接MYSQL的问题,谢谢啦!
- Java连接Elasticsearch6.xxx CRUD篇二
- skywalking搭建与使用
- django 1.8 官方文档翻译: 14-4-1 重定向应用
- 经典机器学习系列(三)【线性模型与广义线性模型】
- ENVI 监督分类Max stdev from Mean 参数IDL中的设置
- XenCenter的安装与使用
- SQLSERVER 查询分析器快捷键
- 解决向日葵远程不能退出腾讯安全管家,点退出时没反应,也不能远程卸载
- 利用matlab实现驻波仿真
- 最近笔记本电脑开机启动正常,进入黑屏?
- Python中uniform的用法
- 人脸识别算法源码SDK开发包人证比对二次开发检测核验开发包
- linux自己的软件在安装的时候如何创建快捷方式,在Deepin Linux系统下给AppImage格式软件创建快捷方式的方法...
- 计算机考试的雷区,驾照场考技巧与科目三电子路考雷区整理
- Rockchip掌机emuelec方案资料及其介绍
- uddi java_使用UDDI4J连接JUDDI
热门文章
- 计算机硬盘的扇区大小,了解硬盘扇区大小(Understanding Hard Disk Sector Size)
- 爱普生曝残墨事件 龚滨良:双重标准损害消费者
- 【Python入门刷题】——NP10 牛牛最好的朋友们
- 如何借助数字签名保护文档安全性
- 电脑常识(1) 32位的电脑和64位的电脑是什么意思?
- 无法删除docker目录(rm: 无法删除/var/lib/docker/overlay/XXXXXXXXXXXXXX/merged: 设备或资源忙)
- 计算机组成原理(一)
- TCP/IP协议和OSI七层模型
- Android网络时间同步
- 『杭电1681』Frobenius