【C语言】qsort()函数详解:能给万物排序的神奇函数

您所在的位置:网站首页 指针函数的例子及解析图解视频 【C语言】qsort()函数详解:能给万物排序的神奇函数

【C语言】qsort()函数详解:能给万物排序的神奇函数

2024-07-12 05:06| 来源: 网络整理| 查看: 265

🦄个人主页:修修修也 🎏所属专栏:C语言 ⚙️操作环境:Visual Studio 2022

一.qsort()函数的基本信息及功能

我们日常生活中经常能碰到需要给一组数据排序的情况,如将班上同学的身高从大到小排序,将淘宝上的商品价格从低到高排序,将班上的同学姓名按首字母顺序排序......随着科学技术的发展,现在这些工作完全可以交给excel一键完成,那么电脑是根据什么程序完成这些排序的? 接下来我们就来给大家介绍一下C语言库函数中可以“给万物排序”的qsort()函数: 先来看一下qsort()函数(quick sort)在百度百科中的定义:

因此,qsort()函数是一个C语言编译器函数库自带的排序函数,它可以对指定数组(包括字符串,二维数组,结构体等)进行排序。

二.常见的排序算法及冒泡排序

我们熟知的数组排序的算法有很多,如冒泡排序,选择排序,直插排序,希尔排序,并归排序,快速排序等,具体八大算法的实现可以移步这篇博客【数据结构】八大排序算法 了解了这些种类繁多的排序算法后,我们希望能够使用一种较为简单的排序算法来实现qsort函数的功能,来模拟实现同样具有可以排序数组,字符串,结构体功能的排序函数。如,我们可以使用冒泡排序的算法来实现具有排序字符串,二维数组,结构体等功能的bubble_sort()函数。 如果还有不太熟悉冒泡排序的朋友可以移步这篇博客【C语言】冒泡排序详解,里面有关于冒泡算法完全0基础的详解,这里就不多赘述了,我们在这里直接演示一下冒泡排序的用法:

冒泡排序算法演示(以升序为例):

数组元素初始顺序如下:

代码语言:javascript复制int arr[10] = { 3,1,5,9,7,6,4,8,0,2 };

冒泡排序(升序)运行结果:

冒泡排序(升序)完整代码如下:

代码语言:javascript复制//冒泡排序 #include void print(int arr[]) { int i = 0; for (i = 0; i (*(Node*)p1).data?1:-1; }

5.对结构体中字符串进行排序:

代码语言:javascript复制struct Node { int data; char str[100]; }s[100]; //按照结构体中字符串str的字典序排序 int comper(const void*p1,const void*p2) { return strcmp((*(Node*)p1).str,(*(Node*)p2).str); }四.使用qsort()函数完成整形,结构体的排序(演示)

了解了qsort()函数的参数及其原理后,我们来尝试使用它完成一些排序任务,以此来熟悉qsort()函数的使用方法。

1.使用qsort()函数完成对一维整形数组的排序:

要使用qsort()函数,就要先准备好它需要的四个参数,即数组的首地址,数组的长度,数组每个元素的长度,还有比较函数的地址(即函数名)。我们依次准备好这四个参数:

接下来就可以调用qsort()函数查看结果了:

可以看到,qsort()函数成功帮我们将该组整形排列成了升序。该部分完整代码如下:

代码语言:javascript复制//使用qsort()函数排序一维数组 #define _CRT_SECURE_NO_WARNINGS 1 #include #include int compar(const void* p1, const void* p2) { return ((*(int*)p1) - (*(int*)p2)); } int main() { int arr[10] = { 3,1,5,9,7,6,4,8,0,2 }; size_t num = sizeof(arr) / sizeof(arr[0]); size_t sz = sizeof(arr[0]); qsort(arr, num, sz, compar); int i=0; for (i = 0; i < num; i++) printf("%d ", arr[i]); return 0; }2.使用qsort()函数完成对结构体的排序:

要使用qsort()函数排序结构体,我们首先要创建一个结构体变量,如下,我们先创建一个包含人名和年龄的结构体变量:

下面会以这个结构体变量为例,分别实现使用qsort()函数完成对结构体按年龄和按姓名的排序。

1>.使用qsort()函数完成对结构体按年龄排序

我们照例先准备好它需要的四个参数,即结构体的首地址,结构体的长度,结构体每个元素的长度,还有比较函数的地址。我们依次准备好这四个参数:

接下来就可以调用qsort()函数查看结果了:

可以看到,qsort()函数帮助我们将该结构体成功按年龄从小到大重新排序了。该部分完整代码如下:

代码语言:javascript复制//使用qsort()函数按年龄排序结构体 #define _CRT_SECURE_NO_WARNINGS 1 #include //创建结构体 struct Stu { char name[20]; int age; }; //compar_按年龄排序 int compar_Stu_age(const void* p1, const void* p2) { return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age; } int main() { struct Stu s[3] = { {"zhangsan",20} ,{"lisi",30},{"wangmazi",25} }; size_t num = sizeof(s) / sizeof(s[0]); size_t sz = sizeof(s[0]); qsort(s, num, sz, compar_Stu_age); for (int i = 0; i < 3; i++) { printf("%s,%d\n", s[i].name, s[i].age); } return 0; }2>.使用qsort()函数完成对结构体按姓名排序

我们照例先准备好它需要的四个参数,即结构体的首地址,结构体的长度,结构体每个元素的长度,还有比较函数的地址。我们依次准备好这四个参数:

需要特别注意按姓名排序的排序函数,因为按姓名排序本质上是给字符串排序,所以我们借助strcmp()函数来比较两个字符串的大小,并将比较的结果返回给qsort()函数。

有关strcmp()函数的相关信息如下:

接下来就可以调用qsort()函数查看结果了:

可以看到,qsort()函数按照名字顺序(字典序)帮助我们成功排好了结构体的顺序,该部分完整代码如下:

代码语言:javascript复制//使用qsort()函数按姓名排序结构体 #define _CRT_SECURE_NO_WARNINGS 1 #include //创建结构体 struct Stu { char name[20]; int age; }; //compar_按姓名排序 int compar_Stu_name(const void* p1, const void* p2) { return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name); } int main() { struct Stu s[3] = { {"zhangsan",20} ,{"lisi",30},{"wangmazi",25} }; size_t num = sizeof(s) / sizeof(s[0]); size_t sz = sizeof(s[0]); qsort(s, num, sz, compar_Stu_name); //打印结果 for (int i = 0; i < 3; i++) { printf("%s,%d\n", s[i].name, s[i].age); } return 0; }五.套用冒泡排序算法,改造并模拟实现qsort()函数

通过上面的例子,我们已经能够熟练使用并足够了解qsort()函数了,接下来我们就可以尝试套用冒泡算法来试试实现bubble_sort()函数了:

1.bubble_sort()函数定义及参数

函数参数没什么好说的,因为要模拟实现qsort()函数,因此直接仿照qsort()函数的参数即可:

代码语言:javascript复制void bubble_sort(void*base, size_t num,size_t sz,int(*compar)(const void*,const void*))2.bubble_sort()函数函数体

函数体内部逻辑整体参考冒泡排序,只在一小部分地方有略微的改动。首先因为我们在整个bubble_sort()函数中都不知道base传进的参数到底是什么类型的,因此索性不去纠结数据的类型,干脆将他们统一视为一个字节一个字节的空间来进行比较及交换,因此传入bubble_sort()函数的指针统一强制类型转换成char*类型,以便后续我们一个字节一个字节操作。该部分代码及解析如下:

代码语言:javascript复制{ size_t i = 0; for (i = 0; i < num - 1; i++) { size_t j = 0; for (j = 0; j < num - 1 - i; j++) { if (compar((char*)base+j*sz,(char*)base+(j+1)*sz) > 0) //因为无法确定base到底代表什么类型的指针,因此不如全部当作字符(只占1字节)指针来处理 { //交换 Swap((char*)base + j * sz, (char*)base + (j + 1) * sz, sz); //交换思路同样是一个字节一个字节交换 } } } }3.bubble_sort()函数中的回调函数Swap()

我们把原本冒泡排序中的交换步骤直接重新分装成一个函数,专门用来交换比较后需要交换的两个元素,同样因为我们并不知道该数据的类型,只知道该数据的大小sz,因此我们不如直接将两个sz大小的字节内容逐个一个字节一个字节逐一交换,这样就能保证不论是什么类型的数据,交换完都不会出现差错了。该部分代码如下:

代码语言:javascript复制//交换函数 void Swap(char* buf1, char* buf2,int sz) { int i = 0; for (i = 0; i < sz; i++) { char tmp = *buf1; *buf1 = *buf2; *buf2 = tmp; buf1++; buf2++; } }六.使用bubble_sort()函数完成整形,结构体的排序(演示)

完成了bubble_sort()函数的编写,接下来我们尝试使用它来代替前面的qsort()函数给数组及结构体进行排序:

1.使用bubble_sort()函数完成对一维整形数组的排序

我们像之前使用qsort()那样准备好bubble_sort()所需要的四个参数:

接下来就可以使用bubble_sort()函数查看结果了:

可以看到,bubble_sort()函数按照整形大小帮我们排好了升序。该部分完整代码如下:

代码语言:javascript复制//使用冒泡排序排列一维数组 #define _CRT_SECURE_NO_WARNINGS 1 #include #include void Swap(char* buf1, char* buf2,int sz) { int i = 0; for (i = 0; i < sz; i++) { char tmp = *buf1; *buf1 = *buf2; *buf2 = tmp; buf1++; buf2++; } } void bubble_sort(void*base, size_t num,size_t sz,int(*compar)(const void*,const void*)) { size_t i = 0; for (i = 0; i < num - 1; i++) { size_t j = 0; for (j = 0; j < num - 1 - i; j++) { if (compar((char*)base+j*sz,(char*)base+(j+1)*sz) > 0) { Swap((char*)base + j * sz, (char*)base + (j + 1) * sz, sz); } } } } int compar(const void* p1, const void* p2) { return ((*(int*)p1) - (*(int*)p2)); } int main() { int arr[10] = { 3,1,5,9,7,6,4,8,0,2 }; size_t num = sizeof(arr) / sizeof(arr[0]); size_t sz = sizeof(arr[0]); bubble_sort(arr, num, sz, compar); int i = 0; for (i = 0; i < num; i++) printf("%d ", arr[i]); return 0; }2.使用bubble_sort()函数完成对结构体的排序

要使用bubble_sort()函数排序结构体,我们首先要创建一个结构体变量,如下,我们先创建一个包含人名和年龄的结构体变量:

下面会以这个结构体变量为例,分别实现使用bubble_sort()函数完成对结构体按年龄和按姓名的排序。

1>.使用bubble_sort()函数完成对结构体按年龄排序

我们照例先准备好它需要的四个参数,即结构体的首地址,结构体的长度,结构体每个元素的长度,还有比较函数的地址。我们依次准备好这四个参数:

接下来就可以调用bubble_sort()函数查看结果了:

可以看到,bubble_sort()函数帮助我们将该结构体成功按年龄从小到大重新排序了。该部分完整代码如下:

代码语言:javascript复制#define _CRT_SECURE_NO_WARNINGS 1 #include #include //交换函数 void Swap(char* buf1, char* buf2, int sz) { int i = 0; for (i = 0; i < sz; i++) { char tmp = *buf1; *buf1 = *buf2; *buf2 = tmp; buf1++; buf2++; } } void bubble_sort(void* base, size_t num, size_t sz, int(*compar)(const void*, const void*)) { size_t i = 0; for (i = 0; i < num - 1; i++) { size_t j = 0; for (j = 0; j < num - 1 - i; j++) { if (compar((char*)base + j * sz, (char*)base + (j + 1) * sz) > 0) { Swap((char*)base + j * sz, (char*)base + (j + 1) * sz, sz); } } } } struct Stu { char name[20]; int age; }; //compar_按年龄排序 int compar_Stu_age(const void* p1, const void* p2) { return ((struct Stu*)p1)->age - ((struct Stu*)p2)->age; } int main() { struct Stu s[3] = { {"zhangsan",20} ,{"lisi",30},{"wangmazi",25} }; size_t num = sizeof(s) / sizeof(s[0]); size_t sz = sizeof(s[0]); bubble_sort(s, num, sz, compar_Stu_age); for (int i = 0; i < 3; i++) { printf("%s,%d\n", s[i].name, s[i].age); } return 0; }2>.使用bubble_sort()函数完成对结构体按姓名排序

我们照例先准备好它需要的四个参数,即结构体的首地址,结构体的长度,结构体每个元素的长度,还有比较函数的地址(即函数名)。我们依次准备好这四个参数:

接下来就可以调用bubble_sort()函数查看结果了:

可以看到,bubble_sort()函数按照名字顺序(字典序)帮助我们成功排好了结构体的顺序,该部分完整代码如下:

代码语言:javascript复制#define _CRT_SECURE_NO_WARNINGS 1 #include #include //交换函数 void Swap(char* buf1, char* buf2, int sz) { int i = 0; for (i = 0; i < sz; i++) { char tmp = *buf1; *buf1 = *buf2; *buf2 = tmp; buf1++; buf2++; } } void bubble_sort(void* base, size_t num, size_t sz, int(*compar)(const void*, const void*)) { size_t i = 0; for (i = 0; i < num - 1; i++) { size_t j = 0; for (j = 0; j < num - 1 - i; j++) { if (compar((char*)base + j * sz, (char*)base + (j + 1) * sz) > 0) { Swap((char*)base + j * sz, (char*)base + (j + 1) * sz, sz); } } } } struct Stu { char name[20]; int age; }; //compar_按姓名排序 int compar_Stu_name(const void* p1, const void* p2) { return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name); } int main() { struct Stu s[3] = { {"zhangsan",20} ,{"lisi",30},{"wangmazi",25} }; size_t num = sizeof(s) / sizeof(s[0]); size_t sz = sizeof(s[0]); bubble_sort(s, num, sz, compar_Stu_name); for (int i = 0; i < 3; i++) { printf("%s,%d\n", s[i].name, s[i].age); } return 0; }七.qsort()的核心:快速排序算法快速排序的思想

快排算法的基本思想是:

通过一趟排序将待排数据分割成独立的两部分其中一部分数据的关键字均比另一部分数据的关键字小可分别对这两部分数据继续进行排序,以达到整个序列有序的目的.

具体的快速排序算法是如何实现的,我放在另一篇博客中了,里面不仅有三种实现快排算法的方式,并且包含了如何使用非递归方式实现快排算法,这里有于篇幅有限,就不对赘述了,感兴趣的朋友可以移步这篇博客: 【数据结构】八大排序之快速排序算法

https://blog.csdn.net/weixin_72357342/article/details/135059337

总结

以上就是关于qsort()函数及其模拟实现bubble_sort()函数的全部内容,希望能对大家有所帮助或有所启发,欢迎各位大佬在评论区或私信与我交流.

有关更多排序相关知识可以移步:

【数据结构】八大排序算法

https://blog.csdn.net/weixin_72357342/article/details/135038495?csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22135038495%22%2C%22source%22%3A%22weixin_72357342%22%7D&fromshare=blogdetail

学海漫浩浩,我亦苦作舟!关注我,大家一起学习,一起进步!

相关文章推荐 【数据结构】八大排序之堆排序算法 【数据结构】八大排序之简单选择排序 【数据结构】八大排序之直接插入排序算法 【数据结构】八大排序之希尔排序算法 【C语言】判断字符类型的三种方法 【C语言】rand()函数(如何生成指定范围随机数) 【C语言】memset()函数 【C语言】strlen()函数 【C语言】memcpy()函数



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3