一、qsort函数声明
qsort是C中自带的快速排序函数,属于标准库<stdio.h>,在做算法题时会比较常用。
本文参考菜鸟教程。
1.函数声明
void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*))
2.参数含义
base: 是指向要排序的数组的第一个元素的指针,其实就是要排序的数组名;
nitems:表示待排序数组中的元素个数;
size: 指数组中每个元素所占的字节长度,可以用sizeof获得;
compar:用来比较两个元素的函数,返回值是int类型,输入的是两个可以指向任何数据类型(void*)的指针,但它们指向的值必须是常量(const)。
(可以看到,函数声明中的compar是一个函数指针的形式,因此可以直接将比较函数作为参数传入)
二、qsort函数用法
1.构造compare函数
int compar(const void *a, const void *b);
compar函数的两个输入a,b其实代表,指向待排序数组中的两个元素的指针。qsort的排序原则是由compar函数返回值决定的。
如果 compar 返回值小于 0(< 0),那么 a 所指向元素会被排在b所指向元素的前面;如果 compar 返回值等于 0(= 0),那么 a 所指向元素与 b 所指向元素的顺序不确定;如果 compar 返回值大于 0(> 0),那么 a 所指向元素会被排在 b 所指向元素的后面。
举个栗子:
// 待排序数组values
int values[] = { 88, 56, 100, 2, 25 };
//定义比较函数
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
(int*)a是对a进行类型转换,使它变为指向原数组中某个元素的指针;原数组元素都是int型,因此a应该变为(int *)。再在前面加*取值。
可以看到在上面这个cmpfunc函数中,当a指向的值大于b指向值时,会返回大于0的数,按照前面的规则,返回值>0,就把a排到b后面。
因此这个函数定义的排序规则,是将values中元素升序排序。
2.数组元素也是数组?
在对数组排序时,可能会出现数组中的元素也是一个数组,我们想要按照数组元素的第一个元素排序。这个在python中很容易实现:
nums = sorted(nums, key=lambda x: x[0])
通过使用lambda对key进行赋值。在C中,compar函数就相当于自定义了lambda,我们同样可以实现上面的效果。
定义compar函数为:
// 待排序数组
int *news[numsSize];
for(int i=0; i<numsSize; i++){
news[i] = malloc(sizeof(int)*2); // 长度为2的数组
}
// 定义比较函数
int compar(const void* a, const void* b)
{
return (*(int**)a)[0] - (*(int**)b)[0];
}
我们定义待排序数组的每个元素都是一个数组,现在想要根据元素的第一维进行升序排序。
那么compar函数中,a的类型应该是(int **),这是因为此时待排序数组中的元素是(int *)类型(整型数组)的。 在前面加了*后,我们可以获取a指向的那个长度为2的数组。
由于我们想要根据元素的第一个值排序,所以用(*(int**)a)[0]取出第一个值进行比较。
可以看到,在对a进行数据类型转换时,只需要明确待排序数组元素的数据类型,再在此基础上加个*表示指针就行。
比如对字符数组排序,就是:
int compar(const void *a, const void *b)
{
return *(char *)a - *(char *)b;
}
其他一些可以参考博文。
总结
qsort函数需要注意的是compar的构造;compar中对输入值的类型转换,以及输出值对排序规则的含义很重要!