目录

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函数的理解和使用相关推荐

  1. C中的qsort函数和C++中的sort函数的理解与使用

    一.qsort()函数 原型:_CRTIMP void __cdecl qsort (void*, size_t, size_t,int (*)(const void*, const void*)); ...

  2. 【C进阶】qsort函数详解

    ⭐博客主页:️CS semi主页 ⭐欢迎关注:点赞收藏+留言 ⭐系列专栏:C语言进阶 ⭐代码仓库:C Advanced 家人们更新不易,你们的点赞和关注对我而言十分重要,友友们麻烦多多点赞+关注,你们 ...

  3. 【C语言】—— qsort()函数的使用

    要学习qsort()函数首先要先了解回调函数 文章目录 一.回调函数 二.qsort函数是什么? 三.用qsort函数排序 1. 整型 2. 结构体 3. 字符型 4. double型 四.具体样例 ...

  4. 【qsort函数实现】

    前言: 首先在进行讲解之前,我们先进行对函数的一些相关介绍,方便大家更好的理解它. 目录 函数介绍 函数实现 函数介绍 第一步: 我们可以先查询知道函数的使用方法: void qsort (void* ...

  5. qsort函数的使用

    今天在刷题时,题目: 输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个.例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323. ...

  6. 实验课题——最全手机通信录实现版本(【含注释】848行代码)!!!(包括模糊查询、分类查找、模拟拨号、qsort函数实现排序、文件存储、防误触等功能)

    目录 简介: 基本要求: 代码的实现: 1.Contact.h 2.test.c 3.Cantact.c 运行效果图: 部分复杂函数流程图 前两周是本人的实验周,抽到的课题是"手机通信录的实 ...

  7. qsort函数详细讲解,各种用法,妙用

    众所周知,在C++中有STL库可以用来进行排序,而对于新手来说很少知道C语言竟然也有自己的排序函数. qsort(基本快速排序的方法,每次把数组分成两部分和中间的一个划分值,而对于有多个重复值的数组来 ...

  8. 趣谈C语言之qsort函数

    在学习c语言的时候,我们接触到了冒泡排序,利用冒泡排序我们可以快速的对一个数组进行大小的比较,可是大家有没有想过一个问题,有没有一种排序方式可以排序任何类型的元素类型的呢?答案是有的,它是qsort函 ...

  9. C语言进阶 -- 回调函数以及qsort函数的使用

    一.回调函数 1.1.什么是回调函数??? 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数.回调 ...

最新文章

  1. 二维费用 hdu 2159 FATE(完全背包)HDU OJ 4501 小明系列故事——买年货【DP】
  2. LSB最低有效位和MSB最高有效位
  3. linq to sql 多条件组合查询
  4. 百度地图mysql打点_关于百度地图连接MYSQL的问题,谢谢啦!
  5. Java连接Elasticsearch6.xxx CRUD篇二
  6. skywalking搭建与使用
  7. django 1.8 官方文档翻译: 14-4-1 重定向应用
  8. 经典机器学习系列(三)【线性模型与广义线性模型】
  9. ENVI 监督分类Max stdev from Mean 参数IDL中的设置
  10. XenCenter的安装与使用
  11. SQLSERVER 查询分析器快捷键
  12. 解决向日葵远程不能退出腾讯安全管家,点退出时没反应,也不能远程卸载
  13. 利用matlab实现驻波仿真
  14. 最近笔记本电脑开机启动正常,进入黑屏?
  15. Python中uniform的用法
  16. 人脸识别算法源码SDK开发包人证比对二次开发检测核验开发包
  17. linux自己的软件在安装的时候如何创建快捷方式,在Deepin Linux系统下给AppImage格式软件创建快捷方式的方法...
  18. 计算机考试的雷区,驾照场考技巧与科目三电子路考雷区整理
  19. Rockchip掌机emuelec方案资料及其介绍
  20. uddi java_使用UDDI4J连接JUDDI

热门文章

  1. 计算机硬盘的扇区大小,了解硬盘扇区大小(Understanding Hard Disk Sector Size)
  2. 爱普生曝残墨事件 龚滨良:双重标准损害消费者
  3. 【Python入门刷题】——NP10 牛牛最好的朋友们
  4. 如何借助数字签名保护文档安全性
  5. 电脑常识(1) 32位的电脑和64位的电脑是什么意思?
  6. 无法删除docker目录(rm: 无法删除/var/lib/docker/overlay/XXXXXXXXXXXXXX/merged: 设备或资源忙)
  7. 计算机组成原理(一)
  8. TCP/IP协议和OSI七层模型
  9. Android网络时间同步
  10. 『杭电1681』Frobenius