提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
随着C语言的学习,我们渐渐也学到了许多排序方法,这里我将介绍一个库函数qsort,他可以对拥有任意类型元素数据的数组进行排序。
一、qsort函数是什么?
qsort是一个库函数,可以直接使用,这个函数可以排序任意类型的数据,这个函数底层使用的是快速排序的方法。
二、qsort函数如何使用?
1.qsort定义
void qsort(void* base, size_t num, size_t size, int(*compar)(const void*, const void*));
首先我们要知道qsort的头文件是 <stdlib.h>,使用它的时候要包含头文件。
我们可以看到,qsort一共有四个参数。那这四个参数都是什么呢?
void* base:这个参数就是要被派排序数组的第一个元素。也就是base存放的是等待排序数组的第一个元素的地址。
size_t num:这个参数表示base指向数组里边的元素个数。
size_t size:这个参数表示被排序数组中一个元素的长度,单位是字节。 比如说如果元素是整形的话,那一个元素长度就是4个字节,如果元素是字符的话,那一个元素长度就是1字节。
int(*compar)(const void*, const void*):这个参数是一个函数指针,返回类型是int型,这个函数指针指向了一个比较函数,这个比较函数用来比较数组中的两个元素。int(*compar)(const void*e1, const void*e2),就比如说e1和e2两个元素,如果e1指向的元素大于e2指向的元素,那么函数就会返回一个大于0的数字,如果e1指向的元素等于e2指向的元素,那么就会返回0,如果e1指向的元素小于e2指向的元素,那么就会返回一个小于0的数字。
也就是说,我们在使用qsort函数的时候,也需要写一个比较函数,然后把比较函数传给qosrt,这样qosrt函数就可以按照我们的比较方法来比较并进行排序。
2.qsort函数的使用
首先我们在使用qsort之前,要知道我们要排序的数组是什么类型,这样到时候给qsort第四个参数传参的时候,才能知道要传可以比较什么类型的比较函数。比如说,我们现在要排一个整型数组:
int arr[10] = { 1,2,5,4,7,8,3,6,9,0 };
那我们就需要写一个可以比较整形类型的比较函数。然后把函数名传给第四个参数:
int cmp_int(const void*e1, const void*e2)//比较整型类型的函数,他的参数需要和qosrt第四个参数所要求的参数一样。
{
}
int main()
{
int arr[10] = { 1,2,5,4,7,8,3,6,9,0 };
int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素个数
qsort(arr, sz, sizeof(arr[0]), cmp_int);//sizeof(arr[0])计算一个元素的大小
return 0;
}
比较函数里边的e1指向一个元素,e2指向一个元素。他们两个进行比较。这个时候我们要进行比较e1和e2的大小。
这时候我们发现*e1那里爆红了,这是为什么呢?其实原因很简单,我们发现e1和e2是什么类型的指针?他们是void*类型的指针,而这种指针只是为了存放一个地址,并不能解引用操作或者加减整数的操作,因为在设计这个qsort函数的时候,并不知道我们要对什么类型的数据进行排序,所以就使用void*的指针进行接收,他可以接受任意类型的指针。
那我们应该怎么办呢?如果想要使用void*类型的指针,我们需要对它进行强制转换类型,这里我们因为要排整形类型的元素,所以就需要把e1,e2指针强制转换成int*,就是这样*(int*)e1 ,*(int*)e2。先把他强制转换成int*,然后再对它解引用。
然后我们继续:
int cmp_int(const void*e1, const void*e2)//比较整型类型的函数,他的参数需要和qosrt第四个参数所要求的参数一样。
{
if (*(int*)e1 > *(int*)e2)
return 1;
else if (*(int*)e1 == *(int*)e2)
return 0;
else
return -1;
}
写成这样我们的比较函数就已经写完了,其实这个比较函数可以再简化一点,既然我们知道e1指向的元素大于e2指向的元素,就返回大于0的数字。相等就返回0 。小于就返回小于0的数字。那我们完全可以写成:
int cmp_int(const void*e1, const void*e2)//比较整型类型的函数,他的参数需要和qosrt第四个参数所要求的参数一样。
{
return *(int*)e1-*(int*)e2;
}
这样是不是也刚好满足要求。这些写完后,我们就可以打印一下数组,看一下qsort有没有帮我们排序好。
我们发现,qsort确实已经帮我们排好了,而且我们发现,qsort默认帮我们排成升序的结果。
那如果我们想让他排降序呢?也很简单,把e1和e2换一下就可以。
int cmp_int(const void*e1, const void*e2)//比较整型类型的函数,他的参数需要和qosrt第四个参数所要求的参数一样。
{
if (*(int*)e2 > *(int*)e1)
return 1;
else if (*(int*)e1 == *(int*)e2)
return 0;
else
return -1;
}
或者
int cmp_int(const void*e1, const void*e2)//比较整型类型的函数,他的参数需要和qosrt第四个参数所要求的参数一样。
{
return *(int*)e2-*(int*)e1;
}
这样就可以排成降序了。
那既然整型数组可以排序,那么不妨我们试一下对结构体数组进行排序呢?
首先,先创建一个结构体数组:
struct stu
{
char name[20];
int age;
};
struct stu s[3] = { {"zhang",20},{"li",18},{"wang",21} };
然后,因为结构体里边有名字还有年龄,我们这里先依据年龄大小进行排序,创建比较函数:
cmp_stu_by_age(const void* e1, const void* e2)
{
return (*(struct stu*)e1).age - (*(struct stu*)e2).age;
}
这里和创建整形比较函数那里逻辑一样,需要先把e1和e2强制转换成结构体指针,然后相减,e1大于e2就会返回大于0的数字,e1等于e2就会返回0,e1小于e2就会返回小于0的数字。那我们看一下是否排序成功。下边是代码和运行截图:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
struct stu
{
char name[20];
int age;
};
cmp_stu_by_age(const void* e1, const void* e2)
{
return (*(struct stu*)e1).age - (*(struct stu*)e2).age;
}
int main()
{
struct stu s[3] = { {"zhang",20},{"li",18},{"wang",21} };
int sz = sizeof(s) / sizeof(s[0]);//计算数组元素个数
qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);//sizeof(arr[0])计算一个元素的大小
for (int i = 0; i < sz; i++)
{
printf("%d ", s[i].age);
}
return 0;
}
显然,排序成功。
那如果我们想依据名字进行排序呢?也不是不行
注意:这里名字是字符串,既然是字符串就不能直接使用>或者<或者==来比较。
而是应该用strcmp函数来进行比较,strcmp函数也是一个库函数,他的头文件是<string.h>。
strcmp函数如何使用呢?首先我们对strcmp函数传入两个字符串,strcmp(字符串1,字符串2),如果字符串1大于字符串2,它会返回大于0的数字。如果字符串1小于字符串2,它会返回小于0的数字,当然,如果相等,返回0;
诶,这样一看,这跟我们比较函数需要返回的不是一样吗?那就方便很多了。话不多说,看代码和运行截图:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct stu
{
char name[20];
int age;
};
cmp_stu_by_name(const void* e1, const void* e2)
{
return strcmp((*(struct stu*)e1).name, (*(struct stu*)e2).name);
}
int main()
{
struct stu s[3] = { {"zhang",20},{"li",18},{"wang",21} };
int sz = sizeof(s) / sizeof(s[0]);//计算数组元素个数
qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);//sizeof(arr[0])计算一个元素的大小
for (int i = 0; i < sz; i++)
{
printf("%s ", s[i].name);
}
return 0;
}
字符串比较其实就是两个字符串相对应位置上的字符比较,比较字符的ASCLL码值,比如说,li和wang,这两个比较'l'和'w'。那个ASCLL码值大,那个就大,如果一样大,就找这两个第二个位置的字符进行比较。
那对字符排序也很简单,就是ASCLL码值相减,然后返回大于0,返回小于0,返回0这样比较大小。下边是ASCLL码值表:
总结
以上就是关于qsort函数的内容,这个库函数可以帮助我们快速的对各种类型的数组进行排序,提高了我们的效率,当然还有许多排序的方法,不一定这个就是最好的,我们也是需要找到最合适的来使用。如果能对您有所帮助,这是我的荣幸!