qsort()是一个排序函数,其内部实现采用的是“快排”,时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),性能远好于冒泡排序( O ( n 2 ) O(n^2) O(n2))。而且可以自定义排序条件,只要理解了qsort(),你就会永远抛弃冒泡。
如果想要学习快排的思想,可以参考:1.6 快速排序 | 菜鸟教程 (runoob.com);
本次串讲中,我们只需要知道:qsort()能够用一种特殊的方式来排序,我们可以手动写cmp函数来控制qsort()的结果。假设对数组a[100]排序,现有 a [ i ] , a [ j ] 且 i < j a[i],a[j]且i
void qsort(
void *base,
size_t nmemb,
size_t size,
int (*compar)(const void *, const void *)
);
//以下解释摘自菜鸟教程
//base -- 指向要排序的数组的第一个元素的指针。
//nitems -- 由 base 指向的数组中元素的个数。
//size -- 数组中每个元素的大小,以字节为单位。
//compar -- 用来比较两个元素的函数。
第一个参数base,为需要排序的空间的起始地址。
int a[100];
qsort(a , nmemb,size,cmp); //表示从a[0]开始排序
qsort(a+1, nmemb,size,cmp); //表示从a[1]开始排序
第二、三个参数要合在一起看才好理解。
第三个参数size,表示每个“排序单元”所占的字节个数,此处“排序单元”意为排序中需要交换时的单元。
第二个参数nmemb,表示一共有多少个“排序单元”参与排序。
size和nmemb的乘积即为需要排序的空间所占的字节数
int a[nmemb];
double b[nmemb];
qsort(a, nmemb , 4, cmp); //一个int所占空间为4个字节
qsort(b, nmemb , 8, cmp); //一个double所占空间为8个字节
qsort(a, nmemb/2 , 8, cmp); //如果这么写,意味着将两个int型变量打包起来,视为一个对象看待。排序中需要交换时会一次换两个int
//第1,3中写法的排序范围都是a[0]~a[nmemb-1],只是解读的方法不一样
第4个参数是理解qsort的关键,其将用于比较两个元素,通过返回值来确定需不需要交换两个元素。
需要明确一个概念,对于一个compare函数,最重要的就是返回值。函数的实现过程不重要,只要能够得到正确的返回值就行。为了得到正确的返回值,定义中间变量、调用其它函数之类的都是可以的。
举个例子:
int cmp(const void *a,const void *b)
{
//为什么有const?const限定一个变量不允许被改变,即只可读。对于cmp这个函数,只需要读指针中的内容确认返回值即可。
//为什么是void?void型指针意为“无类型”指针。这是因为程序不知道排序的单元为int还是double还是我们自己人为凑出来的类型。
//第一步,明确需要排序单元类型
int *aa=(int *)a;
int *bb=(int *)b;
//第二步,比较大小确定返回值
if(*aa>*bb) return 1; //aa指向的元素在b指向的元素之前,目的是升序排序,如果a中的值大,则交换二者,返回正数
return -1; //反之则不交换,返回负数。(相等时不需交换)
}
int main()
{
int a[100];
qsort(a,100,sizeof(a[0]),cmp);//升序排序
}
为什么在解释第三个参数时需要创造出“排序单元”这一定义?是因为这样理解可以方便理解qsort的本质,在使用qsort排序结构体和自己凑的类型时更从容。
例题:现在有一个二维数组 a [ 100 ] [ 3 ] a[100][3] a[100][3],记录了一百个学生的分数,学号,年龄。现在需要你按照学号升序排序。
int cmp(const void *a,const void *b)
{
//第一步,明确要比较对象类型,本题中为“学号”,用int表示
int *aa=(int *)a; //aa此时为某个排序单元 (a[i][0],a[i][1],a[i][2]) 的起始地址,即指向了a[i][0]。
int *bb=(int *)b;
//第二部,将指针指向需要比较的对象
aa=aa+1; //根据学号排序,即根据a[i][1]排序。需要修改指针aa指向的地址,让其从指向a[i][0]变为指向a[i][1]
bb=bb+1;
//第三步,比大小,确定返回值
if(*aa>*bb) return 1;
return -1;
}
int main(){
int a[100][3];
//输入,不写了,假设输完了
qsort(a,100,12,cmp);//有100个排序单元,每个单元12字节(3个int)。也可以写成 sizeof(a[0]) 或者 3*sizeof(int)
}
本文没有介绍如何使用qsort对结构体进行排序,想要了解相关内容可以移步我的另一篇文章->结构体的应用 和 结构体排序(qsort)