零、前言->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;}

才疏学浅,如有纰漏请大佬不吝赐教!