目录
0. 前言
快排是干嘛的,为什么要用快排,用快排的优点是什么???
0.1 快排是干嘛的
给你一个整数数组
nums
,请你将该数组升序排列。nums = [5,2,3,1,4]。我们要做的就是排他!
快排就是用最短的时间将上述数组排序,给他整成nums=[1,2,3,4,5]。
0.2 我们为什么要用快排
你一定听过冒泡排序,选择排序,插入排序等等,但他们实现起来复杂要写一大串代码。
但使用快排的函数---qsort()你仅仅只需要一行代码,就可以完成数组的排序。
0.3 快排的优点是什么
快排的时间复杂度是(n*logn),而像冒泡排序这种排序的时间复杂度是(n*n),在面对数以万计的数据要进行排序时,时间复杂的越小程序运行便可以越快,这种情况下快排的运行效率要远远优于冒泡排序!
如果你还不了解什么是时间复杂的没关系,说白了,快排就像他的名字那样,就是快!就是办事利索!而且活越多(数据越多)就越显它快!在大部分情况下为了优化程序运行效率无脑用它就完事了。
1.qsort(快排)的详解
1.1 qsort函数原型
接下来我们来简单简析下上述参数都具体是什么。我们以数组nums = [5,2,3,1,4]为例分析。
0.首先qsort作为库函数,使用时我们要引入头文件 #include<stdlib.h>
1.void *base 指所需要排序数组的数组首地址(也可以理解为一个指针指向了所需要排序数组的首地址),例如我们要排序数组nums = [5,2,3,1,4],我们在传递实参时就需要在该位置写下nums(指nums的首地址)即可。
2.size_t num 指数组元素个数,如nums数组 num为5,我们可以用num=sizeof(nums)/sizeof(nums[0]) 这个通式求出元素个数。
3.size_t size 指数组中每个元素所占大小(也可以理解为数组的数据类型的大小),我们可以用 size=sizeof(nums[0]) 这个通式来求出每个元素的大小。
4.int (*compar)(const void*,const void*),这个表示为一个函数指针,返回值为int类型。
1_我们先来了解他的返回值的意义
返回值有有三种情况(函数内部会指向两个数进行其大小的比较)
<0 当指向的第一个数小于第二个数会返回一个小于0的数
0 当指向的第一个数等于第二个数会返回一个等于0的数
>0 当指向的第一个数大于第二个数会返回一个大于0的数
在这个函数的内部会根据所返回的值进行排序(此处详请可学习数据结构与算法中的快速排序的实现来了解(有一定的难度))
2_.int (*compar)(const void*,const void*)为函数指针 指向的函数需要我们自己来实现。这样方便我们来实现不同类型数据的排序。以下面的整形排序为例子
行参类型为void*,void*可以表示为任意指针类型(方便对各种类型的元素进行操作),不过void*只能用来指向位置不能解引用来表示该位置的值,所以我们要进行强制类型转换来解读所指向地址的数值。拿 void*e1 举例,我们先用 (int*)e1 将其转换为整形指针,然后再加上一个 * 解引用来解读该地数值 总体表现为 *(int*)e1,即为 e1 所指向的地址的数值
指针e1和e2的指向由函数内部来控制,我们只需了解我们写的这两个指针是为了比较两个元素的大小来实现数组元素的升序排序。同样我们可以观察出来,如果用e2-e1即可实现降序操作。
函数指针所指向的函数的实现:
int cmp(const void* e1, const void* e2) { return *(int*)e1 - *(int*)e2; }
1.2 qsort使用实例
首先我们需要引入qsort的库函数
#include<stdlib.h>
接下来是具体例子:
int cmp(const void* e1, const void* e2) { return *(int*)e1 - *(int*)e2; } int main() { //未排序数组 int num[] = {3,2,1}; //数组长度 int len = sizeof(num) / sizeof(num[0]); //快排 qsort(num,len, sizeof(num[0]), cmp); //展示排序后数组结果 for (int i = 0; i < 3; i++) { printf("%d ", num[i]); } return 0; }
排序结果展示:
这样我们就完成了一次快速排序了
2.qsort(快排)根据不同数据类型的使用
2.0 针对不同数据类型使用快排的实质
基本使用: qsort(数组名,数组个数,数组每个元素的大小,比较函数),从这里可以看出基本只有比较函数需要重写的,所以我们只需要写出针对不同数据类型的比较函数就可以完成快排。所以针对不同数据类型使用快排的实质就是写出不同类型的比较函数。下面我们来做一些示范。
2.1 整形数组排序
如详解中所示例子,在这里再展示一次
int cmp(const void* e1, const void* e2) { return *(int*)e1 - *(int*)e2; } int main() { //未排序数组 int num[] = {3,2,1}; //数组长度 int len = sizeof(num) / sizeof(num[0]); //快排 qsort(num,len, sizeof(num[0]), cmp); //展示排序后数组结果 for (int i = 0; i < 3; i++) { printf("%d ", num[i]); } return 0; }
排序结果展示:
2.2 字符串排序
对于单个字符串内的排我们可以将其看作数组中单个字符的排序,后面会列出多个字符串的排序,请注意区分
//字符快排 int cmp_char(const void* e1, const void* e2) { return *(char*)e1-*(char*)e2; } int main() { char s[] = "acefdb"; //快排 qsort(s, strlen(s), sizeof(s[0]), cmp_char); printf("%s", s); return 0; }
2.3 结构体中的字符串排序(多个字符串排序)
1.首先我们需要将指针类型转换为结构体的类型。
2.因为是对多个整体的字符串排序,所以我们要用到strcmp这个函数来进行比较。(注意与单个字符串的内部排序进行区分!)
//结构体 struct people { int year; char name[20]; }; //结构体字符串快排 int cmp_stu_by_name(const void*e1,const void*e2) { return strcmp(((struct people*)e1)->name, ((struct people*)e2)->name); } int main() { struct people ren[] = { {3,"zhangsan"},{5,"lisi"} }; int sz = sizeof(ren) / sizeof(ren[0]); //结构体字符串快排 qsort(ren, sz, sizeof(ren[0]), cmp_stu_by_name); return 0; }
排序前:
排序后:
可见排序根据首字母大小的顺序进行了排序
3.结语
qsort函数的讲解就到这里,更多数据类型的排序就等着你去实现了。 现在还不了解没关系,拿他当一个工具,先去学会怎么用它就好,在后续的学习中你一定会对这个函数有更深的了解。