qsort()函数(quick sort)是快速排序算法,可以排序任意数据类型的数组其中就包括整形,浮点型,字符串甚至自定义的结构体类型。
下图是4个参数的含义
qsort(void *__base, size_t __nel, size_t __width,int (* _Nonnull __compar)(const void *, const void *));
1. void*base (首元素地址)
我们要排序一个数组,首先要知道从哪儿开始排序,所以先把首元素地址传给qsort函数。
2.size_t nell (元素个数)
我们还要知道数组从哪里结束,但是由于排序的不确定性我们不清楚最后的元素地址,所以将元素个数传入qsort函数。
3.size_t width (元素字节大小)
我们知道qsort函数可以排序任意类型的一组数据,因此我们采用void*类型的指针接收元素,但是void*类型的指针不能进行加减操作,也就无法移动。
那么在函数内部又是怎样操作变量的呢?
我们可以将void*类型的指针强制类型转换char*类型的指针后来操作元素。因为char*类型的指针移动一次的单位是一个字节,因此得知要操作的元素字节大小时,就可以让char*类型的指针移动该个字节到下一个元素,指针就可以指向那个元素了。
4.int (* _Nonnull __compar)(const void *, const void *))(比较函数)
我们要怎么给一组数据排序呢?例如可以给整形数据从小到大,也可以给浮点型数据从大到小,或者还可以比较字符串的大小也可以比较字符串的长度。这些我们就必须要写一个比较函数了。
具体的使用
要使用qsort函数我们要引用一个头文件
#include
比如我们要排序一个整形元素的数组
#include #include int compar(const void *e1, const void *e2){return (*(int *)e1 - *(int *)e2);}int main(){int arr[5] = {5, 2, 1, 4, 3};qsort(arr, 5, sizeof(arr[0]), compar);for (int i = 0; i < 5; i++){printf("%d ", arr[i]);}return 0;}
打印出来的结果:
可以看到升序排列,而改变成降序排列只需要改变compar里的内容即可。
#include #include int compar(const void *e1, const void *e2){return -((*(int *)e1 - *(int *)e2));}int main(){int arr[5] = {5, 2, 1, 4, 3};qsort(arr, 5, sizeof(arr[0]), compar);for (int i = 0; i < 5; i++) {printf("%d ", arr[i]);}return 0;}
可见,将return的值加上负号就能改变排列顺序,那么究竟是什么原因呢?接下来,我为大家用冒泡排序的方法实现这个函数。
#include #include //交换函数的实现void Swap(char *buf1, char *buf2, int width){while (width){char box = *buf1;*buf1 = *buf2;*buf2 = box;buf1++;buf2++;width--;}}//比较函数的实现int cmp(const void *e1, const void *e2){return *(int *)e1 - *(int *)e2;}void bubble_sort(void *base, int sz, int width, int (*cmp)(const void *, const void *)){int i, j = 0;for (i = 1; i < sz; i++){for (j = 0; j 0){// 满足上述条件,开始排序Swap((char *)base + j * width, (char *)base + (j + 1) * width, width);}}}}int main(){int arr[5] = {4, 3, 1, 2, 5};int sz = sizeof(arr) / sizeof(arr[0]);bubble_sort(arr, sz, sizeof(arr[0]), cmp);for(int i=0; i<5; i++){printf("%d ",arr[i]);}return 0;}
所以根据上述函数的内部实现可以得出return的数值如果大于0,那么就进行交换并且实现排序。那么如果想要反方向排序的话,只需要让return的数值取负值,及前一个数比后一个数小就交换,及降序排序。
各种类型的cmp函数实现(除了整型,上面已包含)
1.浮点型
int cmp(const void *e1, const void *e2){ return (int)(*(float*)e1 - *(float*)e2);}
2.比较字符串大小
int cmp(const void *e1, const void *e2){return strcmp((char*)e1,(char*)e2);}
3.比较字符的长度
int cmp(const void *e1, const void *e2){return strlen((char*)e1) - strlen((char*)e2);}
4.比较结构体变量
int cmp(const void *e1, const void *e2){return (int)(((stu*)e1)->weight - ((stu*)e2)->weight);}