首页 > 编程知识 正文

c语言qsort函数对结构体排序,qsort函数和sort函数

时间:2023-05-04 02:49:32 阅读:263105 作者:2793

文章目录 一、qsort函数介绍二、qsort函数传参内容分析三、总体思路与注意事项四、对多种数据类型进行排序1.对int型数组排序2.对char型数组排序3.对double型数组排序4.对字符串型数组排序5.对结构体排序 模仿qsort函数


一、qsort函数介绍

我们在此之前应该大概了解过多种排序的方法,例如最常见的冒泡排序,选择排序,归并排序等等,而利用qsort函数实现排序简称快速排序。它的计算速度非常快,所以系统也在库里实现这个算法,便于我们的使用。它是ANSI C标准中提供的,其声明在stdlib.h文件中,是根据二分法写的,其时间复杂度为n*log(n)。

功能:qsort()函数是 C 语言库中实现的快速排序。

头文件: stdlib.h

函数原型:
void qsort(void *base, size_t nmemb, size_t size, int (*compar)(const void *, const void *));


可见,当我们要使用qsort函数进行快速排序时,必须要传4个参数给qsort函数接收,单单看函数原型可能大部分读者都不是特别理解,下面就由我来引导大家如何准确使用qsort函数。
二、qsort函数传参内容分析

1.第一个参数是需要排序的数组的基地址,而我们知道,当我们在主函数中传参时是数组名,则传到自定义函数体中则是该数组的首元素地址,而我们观察是void*类型,因此我们传过去的数组类型不限(即任意数组类型)。

2.第二个参数是待排序的数量,即你要将数组中要排序的数量传进qsort函数中,而类型是size_t,表示的是无符号整型,传一个正数到qsort函数即可。

3.第三个是单个数组元素的大小,即字节数,数组元素的大小用sizeof操作符进行计算,格式是sizeof(数组名[0])。

4.第四个参数是一个指向函数的指针,其作用是规定排序的规则,即按照什么样的方式进行排序。这里光看概念不容易看懂,最好用例子来进行实现。


三、总体思路与注意事项

先创建整型数组,初始化值,将调用qsort函数所需的四个参数依次填入,要按规定的顺序进行传参。由于调用qsort函数时要调用另一个函数返回所需的值进行升序或降序排序(以下举例均为mycmp函数)。在mycmp函数中固定要用两个参数接收 。const的作用只是让程序员不能改变该地址,不必想的过于复杂,其实const是否加上不影响结果,但为了严谨最好加上const。
在mycmp函数中,我参考了许多篇文章都写得太过冗余与复杂,并且代码量比较大。特别是*a 与 *b 的比较之后返回给qsort参数的值写的太乱,在这里我对此做个总结。以下的代码 *a 与 *b的比较, *a是一定大于 *b的,如果我们想让排序为升序,则返回1,降序则返回-1,只需将 *a 与 *b的位置调换即可。这里我们可以在所有利用三目操作符来实现避免if语句的繁琐。


四、对多种数据类型进行排序 1.对int型数组排序 #include <stdio.h>#include <stdlib.h>int mycmp(const void* p1, const void* p2)//固定格式{const int* a = (const int*)p1;//将p1、p2强制类型转换const int* b = (const int*)p2; int value = 0; value = * a > * b ? 1 : -1;return value;//升序返回1,降序返回-1}int main(){int num[3] = { 2,5,3 }; qsort(num, 3, sizeof(num[0]), mycmp);for (int i = 0; i < 3; i++){printf("%d ", num[i]);}return 0;}

代码实现结果如图:

2.对char型数组排序 #include <stdio.h>#include <stdlib.h>int mycmp(const void* p1, const void* p2){const char* a = (const char*)p1;const char* b = (const char*)p2;int value = 0; value = * a > * b ? 1 : -1;return value;}int main(){ char num[] = {'a','c','b'}; qsort(num, 3, sizeof(num[0]), mycmp);for (int i = 0; i < 3; i++){printf("%c ", num[i]);}return 0;}

代码实现结果如图:

3.对double型数组排序

补充:在double中如果是两个很接近的数则可能返回一个很小的小数(大于-1,小于1),而cmp的返回值是int型,因此会将这个小数返回0,系统认为是相等,失去了本来存在的大小关系,因此此处必须要使用三目操作符进行判断。

#include <stdio.h>#include <stdlib.h>int mycmp(const void* p1, const void* p2){ const double* a = (const double*)p1;const double* b = (const double*)p2;int value = 0; value = * a > * b ? 1 : -1;return value;}int main(){ double num[] = { 3.0,5.0,7.0 }; qsort(num, 3, sizeof(num[0]), mycmp);for (int i = 0; i < 3; i++){printf("%lf ", num[i]);}return 0;}

代码实现结果如图:

4.对字符串型数组排序 #include <stdio.h>#include <stdlib.h>int mycmp(const void* p1, const void* p2){ const char* a = (const char*)p1;const char* b = (const char*)p2;int value = 0; value = * a > * b ? 1 : -1;return value;}int main(){ char num[100][10] = {"ab","ef","cd"};qsort(num, 3, sizeof(num[0]), mycmp);for (int i = 0; i < 3; i++){printf("%s ", num[i]);}return 0;}

代码实现结果如图:

5.对结构体排序 #include <stdio.h>#include <stdlib.h>struct Stu{char name[20];int age;};int mycmp_struct(const void* p1, const void* p2)//固定格式{return ((struct Stu*)p1)->age-((struct Stu*)p2)->age;//升序}int main(){struct Stu s[2] = { {"zhangsan",15},{"lisi",13} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), mycmp_struct);return 0;}

经过调试最后发现,zhangsan和lisi的年龄调换了位置(即升序),如果想要降序,则在 return ((struct Stu*)p1)->age-((struct Stu*)p2)->age; 处调换p1与p2的位置即可。

如果想让结构体中的字符串进行升序排序

#include <stdio.h>#include <stdlib.h>struct Stu{char name[20];int age;};int mycmp_struct(const void* p1, const void* p2)//固定格式{return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);}int main(){struct Stu s[2] = { {"zhangsan",15},{"lisi",13} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), mycmp_struct);return 0;}

模仿qsort函数

前面我们已经对qsort函数有了一定的介绍。模仿qsort函数我们要求一样能够解决不同类型的数据排序。这里我们直接用int数组进行升序排列,先看代码。

#include <stdio.h>void Swap(char* buf1, char* buf2, int width){int i = 0;for (i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}}int cmp_int(const void* e1, const void* e2){return ((*(int*)e1) - *(int*)e2);}void my_qsort(void* base, size_t sz, size_t width, int(*cmp)(const void*,const void*)){size_t i = 0;for (i = 0; i < sz - 1; i++){size_t j = 0;for (j = 0; j < sz - 1 - i; j++){if (cmp((char*)base + j * width, (char*)base + (j + 1) * width)){Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);}}}}int main(){int arr[] = { 3,2,1 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);my_qsort(arr, sz, sizeof(arr[0]), cmp_int);for (i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;}

在此我用my_qsort函数来模仿库函数的qsort,我们传的参数跟库函数中的qsort函数是一致的,只是在my_qsort函数内部有所不同。

相信读者阅读到此篇文章的程度,对冒泡排序一定非常熟悉。都是先考虑一个数一共有几趟需要排序,而一趟排序当中又要有几对数要进行比较,如果前者比后者大,则大的数向后移动,直到没有数比较为此,以此类推。

冒泡排序的代码如下:

void bubble_sort(int arr[], int sz){//趟数int i = 0;for (i = 0; i < sz - 1; i++){//一趟冒泡排序int j = 0;for (j = 0; j < sz-1-i; j++){if (arr[j] > arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}}

模仿qsort函数最巧妙的地方就在于if语句的判断内容以及Swap函数是如何交换的。在if语句中,我们用cmp的返回值来进行判断,如果升序则返回大于0的数,降序则返回小于0的数。我们在对两个值进行比较时,无法判断这两个数值的类型是什么,这里我们将base指针强制类型转换为char来进行比较。每个不同的数据类型的指针决定的是+1移动的是多少个字节。char每次加1就移动1个字节。而width又是每个值的字节数,因此我们用(char*)base+jwidth与(char)base+(j+1)*width来实现两个值的比较(无论是结构体的字符串类型还是整型都能够比较)(j+1是指前后两位的比较,例如3,5,6。是3和5的比较)。

进入判断部分后要进行交换。交换时我们要把两个数值的地址传进Swap函数中,注意这里还要把它们的宽度(一个值的字节数)传进去,并用两个char型指针与width接收。Swap函数内部利用循环并且用char类型来每一个字节进行比较,直到所有字节交换完毕后,即两个值已经完全进行交换,退出循环。


如果对本文有什么补充与不足欢迎前来讨论,如果本文对您在qsort函数的理解上有帮助,请给个赞支持下谢谢!快三技巧准确率100stdlib.h>struct Stu{char name[20];int age;};int mycmp_struct(const void* p1, const void* p2)//固定格式{return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);}int main(){struct Stu s[2] = { {"zhangsan",15},{"lisi",13} };int sz = sizeof(s) / sizeof(s[0]);qsort(s, sz, sizeof(s[0]), mycmp_struct);return 0;}

模仿qsort函数

前面我们已经对qsort函数有了一定的介绍。模仿qsort函数我们要求一样能够解决不同类型的数据排序。这里我们直接用int数组进行升序排列,先看代码。

#include <stdio.h>void Swap(char* buf1, char* buf2, int width){int i = 0;for (i = 0; i < width; i++){char tmp = *buf1;*buf1 = *buf2;*buf2 = tmp;buf1++;buf2++;}}int cmp_int(const void* e1, const void* e2){return ((*(int*)e1) - *(int*)e2);}void my_qsort(void* base, size_t sz, size_t width, int(*cmp)(const void*,const void*)){size_t i = 0;for (i = 0; i < sz - 1; i++){size_t j = 0;for (j = 0; j < sz - 1 - i; j++){if (cmp((char*)base + j * width, (char*)base + (j + 1) * width)){Swap((char*)base + j * width, (char*)base + (j + 1) * width,width);}}}}int main(){int arr[] = { 3,2,1 };int i = 0;int sz = sizeof(arr) / sizeof(arr[0]);my_qsort(arr, sz, sizeof(arr[0]), cmp_int);for (i = 0; i < sz; i++){printf("%d ", arr[i]);}return 0;}

在此我用my_qsort函数来模仿库函数的qsort,我们传的参数跟库函数中的qsort函数是一致的,只是在my_qsort函数内部有所不同。

相信读者阅读到此篇文章的程度,对冒泡排序一定非常熟悉。都是先考虑一个数一共有几趟需要排序,而一趟排序当中又要有几对数要进行比较,如果前者比后者大,则大的数向后移动,直到没有数比较为此,以此类推。

冒泡排序的代码如下:

void bubble_sort(int arr[], int sz){//趟数int i = 0;for (i = 0; i < sz - 1; i++){//一趟冒泡排序int j = 0;for (j = 0; j < sz-1-i; j++){if (arr[j] > arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}}

模仿qsort函数最巧妙的地方就在于if语句的判断内容以及Swap函数是如何交换的。在if语句中,我们用cmp的返回值来进行判断,如果升序则返回大于0的数,降序则返回小于0的数。我们在对两个值进行比较时,无法判断这两个数值的类型是什么,这里我们将base指针强制类型转换为char来进行比较。每个不同的数据类型的指针决定的是+1移动的是多少个字节。char每次加1就移动1个字节。而width又是每个值的字节数,因此我们用(char*)base+jwidth与(char)base+(j+1)*width来实现两个值的比较(无论是结构体的字符串类型还是整型都能够比较)(j+1是指前后两位的比较,例如3,5,6。是3和5的比较)。

进入判断部分后要进行交换。交换时我们要把两个数值的地址传进Swap函数中,注意这里还要把它们的宽度(一个值的字节数)传进去,并用两个char型指针与width接收。Swap函数内部利用循环并且用char类型来每一个字节进行比较,直到所有字节交换完毕后,即两个值已经完全进行交换,退出循环。


如果对本文有什么补充与不足欢迎前来讨论,如果本文对您在qsort函数的理解上有帮助,请给个赞支持下谢谢!

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。