引言
① qsort 是一个库函数,头文件是 <stdlib.h>.
② qsort 是基于快速排序算法的排序函数。
一、了解qsort函数
void qsort (void* base, // 1 size_t num, // 2 size_t size, // 3 int (*compare)(const void* a,const void* b)); // 4 // 1. base 表示的是数组首元素的地址,一般为数组名 // 2. num 表示的是数组中元素的个数 // 3. size 表示的数组中每个元素所占内存的字节大小 // 4. compare 表示一个函数指针,指向自定义函数的地址。也就是说,使用什么样的自定义函数,直接传过来给 qsort 调用即可。
注意事项:
① compare 参数可以这么做:我们自己进行创建的一个函数 function,然后把 function 的地址作为 qsort 的 compare 参数。(这需要理解函数指针的知识,如果不理解也没关系,直接传函数名,也可以表示函数的地址)
② 自定义函数的形参为 a 和 b,它们都是 void* 指针类型。这么设计的原因就是:待排序的数据不确定,(可能是整型、浮点型、字符…)。后期在自定义函数中,先强制转换,再解引用也可以很好地比较元素。
二、使用qsort函数对数组中的各种类型进行排序
1. 整型元素排序
#include <stdio.h> #include <stdlib.h> int compare(const void* a, const void* b); int main(void) { int arr[] = { 9,7,8,4,5,6,1,2,3,0 }; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr,sz, sizeof(int), compare); int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; } int compare(const void* a, const void* b) { return (*(int*) a - *(int*) b); } //解释 qsort(arr,sz, sizeof(int), compare); //1. arr是数组名,表示首元素的地址 //2. sz表示数组中所有元素的个数,这里sz = 10 //3. sizeof(int)是计算数组中的每个元素是多少字节的 //经计算后是4个字节,或者写成 sizeof(arr[0]) //4. compare表示我们自己创建的一个函数 //规则就是接收两个无符号指针类型,目的在于排序任何类型的变量 //5. 解释 return (*(int*) a - *(int*) b); //(1)将其先强制转换成int* 指针,目的是确定元素的类型为 int //(2)再解引用,目的是通过指针找到数组中的元素 //(3)最后返回
输出结果:
注:如果我们把a和b调换位置,那么就会进行降序操作
#include <stdio.h> #include <stdlib.h> int compare(const void* a, const void* b); int main(void) { int arr[] = { 9,7,8,4,5,6,1,2,3,0 }; int sz = sizeof(arr) / sizeof(arr[0]); qsort(arr,sz, sizeof(int), compare); int i = 0; for (i = 0; i < sz; i++) { printf("%d ", arr[i]); } printf("\n"); return 0; } int compare(const void* a, const void* b) { return (*(int*) b - *(int*) a); }
输出结果:
2. 字符串中的字符元素排序
#include <stdio.h> #include <string.h> #include <stdlib.h> int compare(const void* a, const void* b); int main(void) { char arr[] = "adgcefb"; int len = strlen(arr); qsort(arr, len, sizeof(char), compare); printf("%s\n", arr); return 0; } int compare(const void* a, const void* b) { return strcmp((char*)a, (char*)b); //用strcmp比较字符串 } //解释 qsort(arr, len, sizeof(char), compare); //1. arr是数组名,表示首元素的地址 //2. len表示数组中待排序的字符的格式,不包括'\0' //3. sizeof(char)是计算数组中的每个元素是多少字节的,经计算后是1个字节 //或者写成sizeof(arr[0]) //4. compare表示我们自己创建的一个函数 //规则就是接收两个无符号指针类型,目的在于排序任何类型的变量 //5. 解释 return strcmp((char*)a, (char*)b); //(1)将其先强制转换成char* 指针,目的是确定元素的类型为 char //(2)再解引用,目的是通过指针找到数组中的元素 //(3)最后返回 //这里用到了strlen函数和strcmp函数,不再展开讲
注:如果我们把a和b调换位置,那么仍然会进行降序操作
3. 结构体元素排序
1. 排序结构体中的字符
(1) 我们先创建一个 struct stu 类型的结构体,里面分别有名字、年龄、成绩 这三个变量
(2) 之后创建一个结构体数组,即用数组装了三个结构体变量
(3) 下面代码,目的是为了把人的名字进行排序,然后展示出来
这就好像我们大一在学校一样,用姓氏来排名
所以我创建了一个 comparebyname 函数进行排序
#include <stdio.h> #include <string.h> #include <stdlib.h> int comparebyname(const void* a, const void* b); struct stu { char name[20]; int age; float grade; }; int main(void) { struct stu arr[3] = { {"mingming",23,85}, {"yueyue", 20, 87},{"lili", 26, 90} }; int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; for (i = 0; i < sz; i++) { printf("%-15s %-10d %-10f\n", arr[i].name, arr[i].age, arr[i].grade); } printf("\n"); qsort(arr, sz, sizeof(struct stu), comparebyname); for (i = 0; i < sz; i++) { printf("%-15s %-10d %-10f\n", arr[i].name, arr[i].age, arr[i].grade); } return 0; } int comparebyname(const void* a, const void* b) { return strcmp(((struct stu*)a)->name, ((struct stu*)b)->name); } //解释 qsort(arr, sz, sizeof(struct stu), comparebyname) //1. arr是数组名,表示首元素的地址 //2. sz表示数组中所有元素的个数,这里sz = 3 //3. sizeof(struct stu)是计算数组中的每个元素是多少字节的,经计算后的值是28个字节 //(结构体内存对齐) //这里的数组中每个元素是结构体变量,所以就是这么求得的,或者写成sizeof(arr[0]) //4. comparebyname表示创建一个函数,规则就是以字符串的首字符来进行排序整个数组 //5. return strcmp(((struct stu*)a)->name, ((struct stu*)b)->name); //(1) (struct stu*)a 将无符号指针强制转换成一个结构体指针,目的是确定元素的类型 //(2) ((struct stu*)a)->name 访问结构体成员变量 //(3) strcmp()接收的是两个地址,也就是指针类型 //(4) 这其中的name表示的是数组首元素的地址,所以符合strcmp要求
输出结果:
字符升序
l - m - y
同一个想法,不同逻辑
接着,我使用以年龄为排序方式
2. 排序结构体中的整型
同理,我创建了一个 comparebyage 函数
#include <stdio.h> #include <string.h> #include <stdlib.h> int comparebyage(const void* a, const void* b); struct stu { char name[20]; int age; float grade; }; int main(void) { struct stu arr[3] = { {"mingming",23,85}, {"yueyue", 20, 87},{"lili", 26, 90} }; int sz = sizeof(arr) / sizeof(arr[0]); int i = 0; for (i = 0; i < sz; i++) { printf("%-15s %-10d %-10f\n", arr[i].name, arr[i].age, arr[i].grade); } printf("\n"); qsort(arr, sz, sizeof(struct stu), comparebyage); for (i = 0; i < sz; i++) { printf("%-15s %-10d %-10f\n", arr[i].name, arr[i].age, arr[i].grade); } return 0; } int comparebyage(const void* a, const void* b) { return (*(struct stu*)a).age - (*(struct stu*)b).age; } //解释 qsort(arr, sz, sizeof(struct stu), comparebyage) //1. arr是数组名,表示首元素的地址 //2. sz表示数组中所有元素的个数,这里sz = 3 //3. sizeof(struct stu)是计算数组中的每个元素是多少字节的,经计算后的值是 28个字节 //这里的数组中每个元素是结构体变量,所以就是这么求得的,或者写成sizeof(arr[0]) //4. comparebyage表示创建一个函数,规则就是以成绩的大小来进行排序整个数组 //5. return (*(struct stu*)a).age - (*(struct stu*)b).age; //(1) (struct stu*)a 将无符号指针强制转换成一个结构体指针,目的是确定元素的类型为 //(2) (*(struct stu*)a).age 访问结构体成员变量 // age 是一个整型变量,所以必须解引用指针,然后访问的才是元素 //(3) 两个整型,在这qsort逻辑里面,直接用减号比较,然后返回就行了
输出结果:
数字升序
20 - 23 - 26
总结
1. 本文意在表达如何正确、简单地使用qsort函数,并不打算介绍 qsort 函数内部算法的功能。qsort 函数是基于升序算法的,感兴趣的小伙伴可以模拟一下函数。
2. 本文没有讲到浮点类型的排序,因为它的逻辑和整形元素其实是一样的。
3. 本文用到了字符串函数,有如strlen、strcmp,这些并没有展开讲,不熟悉的小伙伴可以去MSDN,或者 cplusplus.com 去看一下,本文的 qsort函数 详细说明也可以看到介绍。
4. 本文也用到了数组、指针、结构体的一些知识,并将它们串了起来,对复习之前的C语言知识还是有亿点点帮助的,哈哈哈。
Over. 谢谢观看哟~