零、前言->qsort函数能干嘛?
很多新手和小白在学习和使用C语言的过程中,面对各种类型的数据需要进行排序时,很难一次性的把各种类型的数据一次性排序。
只要你刚学过C语言的函数基本规则,就能使用它。qsort函数简单易上手,此篇文章将让读者能够入门使用qsort函数,帮你解决数据排序的烦恼!
一、了解->什么是qsort(quick sort)函数?(不想了解的可以直接跳到第二节)
在官方的Cpp网站中,对qsort函数的定义如下:
原文请点击:
cplusplus.com/reference/cstdlib/qsort/
给出了形参,就等于告诉了我们怎么使用这个函数。
————未月五(shenjingbing)
qsort函数的形参由四部分组成:
1.void* base:
需要排序的数组的首元素地址。
之所以写成void*,是因为该形参可以接收任何种类的地址(如char* ,int*都可以被*void*接收),也就能够进行各种数据类型(整型、字符型、浮点型、结构体等等)的排序了。
base(译为基础),非要理解的话,在这里可以理解成数组的首元素。
2.size_t num:
需要排序的数组的元素个数。size_t是unsigned int(无符号整型)的意思。
通常用以下代码来计算元素个数:
int arr[] = { 9,8,7,6,5,4,3,2,1,0 };//以该数组为例int sz = sizeof(arr) / sizeof(arr[0]);
3.size_t size
需要排序的数组内每个元素的字节大小。
通常用sizeof(arr[0]来表示每个元素字节大小。
4.int(*compar)(const void*,const void*)
自定义的compar函数。不要看见自定义就犯愁,其实很简单!
int(*compar)(const void*,const void*)是一个函数指针,指向compar函数。不了解函数指针的读者没有关系,下文会讲解怎么使用。
因为qsort函数不知道我们需要排序的数组是什么数据类型,(是char、int还是结构体呢?)所以让我们自己定义compar函数,才能实现各种数据类型的排序。
上面也提过,之所以写成void*,是因为该形参可以接收任何种类的地址(如char* ,int*都可以被*void*接收),也就能够进行各种数据类型(整型、字符型、浮点型、结构体等等)的排序了。
那么如何自定义compar函数呢” />
原文请点击:
cplusplus.com/reference/cstdlib/qsort/
qsort函数要求自定义的compar函数返回值分成三种:
图3
(还是以整型数组为例)
翻译成人话,就是定义的时候,如果前面的元素比后面的元素小,需return小于0的值;
如果相等,需要返回0;
如果前面的元素比后面的元素大,需return大于0的值。
int cmp_int(const void* p1, const void* p2)//以int类型数据为例{return *(int*)p1 - *(int*)p2;}
所以作差是定义compar函数一种比较好的方式。(注意,double数组千万不能作差!要用三目操作符:)
在对浮点或者double型的一定要用三目运算符,因为如果也使用整型那样的想减的话,如果是两个很接近的数则可能返回一个小数(大于-1,小于1),而cmp的返回值是int型,因此会将这个小数返回0,系统认为是相等,失去了本来存在的大小关系。
原文链接(感谢大佬指点):
qsort细节用法,double型的排序我竟然一直用错了~~~_qt 浮点数排序-CSDN博客
compar函数的形参是数组的前后两个元素(*p1和*p2在qsort函数内部已经和自定义的compar函数进行过联系了),本例子是int类型的数组,所以有强制转换成int*的操作。再对强制转换成int*的指针变量p进行解引用,就可以得到图3qsort函数要求的返回值。
下面就讲一讲怎么使用qsort函数。
二、qsort函数的使用(不用看本文第一节,直接套就行)
Step1:加上#include头文件
Step2:确定你的数组是什么数据类型(int arr[10]、double arr[10]、chararr[10]等等)
int arr[10] = { 33,24,53,53,67,44,24,22,312,36};
这就是int
double arr[10] = { 1.22,2.33,3.44,4.55,5.66,6.77,7.88,8.99,9.11,10.33};
这是double
struct Stu{char name[20];int age;};struct stu s[] = { {"mingming",13},{"xiaomei",15},{"lihua",40}};//李华应该得40了吧
这是结构体
Step3:自定义cmp函数(默认升序,想要做降序排列,就把p1改成p2,p2改成p1)
int cmp_int(const void* p1, const void* p2){return (*(int*)p1 - *(int*)p2);}
这是int,常用作差法
int cmp_double(const void* p1, const void* p2){return *(double*)p1 > *(double*)p2 " />常用三目操作符
int cmp_stu_by_name(const void* p1, const void* p2){return strcmp(((struct Stu*)p1)->name , ((struct Stu*)p2)->name);}
这是结构体的字符串,用strcmp函数(需头文件#include)对两个字符串进行比较(按26个字母的顺序进行排序,第一个字母相同就再比下一个字母)
Step4:套进qsort函数里
qsort(arr, sz, sizeof(arr[0]), cmp_int);//cmp_int是step3自定义的函数名字
分别写四个参数:qsort(数组名,元素个数,每个元素的字节大小,compar函数的名字);
Step5:打印出来验证一下排序是否成功
注意我测试的是整型,所以是int arr[]和%d打印。如果测试double型要灵活改动(下面有示例)
void print(int arr[], int sz)//注意我测试的是整型,所以是int arr[]。如果测试double型要灵活改动{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);//如果是double型要改成%lf,其他类型同理}
示例:
int型
#include#include//qsort函数需要该头文件来实现int cmp_int(const void* p1, const void* p2){return (*(int*)p1 - *(int*)p2);}void print(int arr[], int sz){int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}}tese_int() //把整型数组排序放在一个模块里面测试{int arr[10] = { 33,24,53,53,67,44,24,22,312,36};//需要排序的乱序int型数组;int sz = sizeof(arr) / sizeof(arr[0]);qsort(arr, sz, sizeof(arr[0]), cmp_int);print(arr, sz);//打印排序好的数组}int main(){tese_int();return 0;}
double型
#include#includeint cmp_double(const void* p1, const void* p2){return *(double*)p1 > *(double*)p2 " />
结构体(字符串)
#include#include//qsort函数需要该头文件来实现#includestruct stu{char name[20];int age;};int cmp_stu_by_name(const void* p1, const void* p2){return strcmp(((struct stu*)p1)->name, ((struct stu*)p2)->name);}void test_struct_by_string(){struct stu s[] = { {"mingming",13},{"xiaomei",15},{"lihua",40} };//李华应该得40了吧int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);}int main(){//tese_int();//test_double();test_struct_by_string();return 0;}
才疏学浅,如有纰漏请大佬不吝赐教!