一、qsort函数简介
1.'qsort'函数是C标准库中用于对数组进行排序的函数。使用快速排序算法(quicksort)算法,这是一种高效的排序算法。
2.可以对任意类型的数据进行排序,因为它使用了比较函数指针来决定元素的相对顺序。
3.它声明在<stdlib.h>头文件中。
4.函数原型
void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void*,const void*) );
(1)'base':指向要排序的数组的其实地址
(2)'nmemb' :数组中元素的个数
(3)'size':每个元素的大小(以字节为单位)
(4)'compar':比较函数,用于确定两个元素的相对顺序
5.比较函数
比较函数需要比较两个元素,并返回一个整数:
(1)第一个元素<第二个元素,返回负值(<0)。
(2)第一个元素=第二个元素,返回0。
(3)第一个元素>第二个元素,返回正值(>0)。
二、qsort函数具体使用举例
1.对'int'类型排序
#include<stdio.h>
#include<stdlib.h>
//比较函数:比较两个整数
int compare_ints(const void* a, const void* b)
{
int int_a = *(int*)a;
int int_b = *(int*)b;
return (int_a > int_b) - (int_a < int_b);
}
int main()
{
int arr[] = { 4,2,3,1,5 };
//计算数组中元素的个数
size_t arr_size = sizeof(arr) / sizeof(arr[0]);
//调用qsort进行排序
qsort(arr, arr_size, sizeof(int), compare_ints);
//打印排序后的数组
for (int i = 0; i < arr_size; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
(1)运行结果:
(2)代码解释:
int compare_ints(const void *a, const void *b);
①'const void *a':指向第一个比较的元素。使用'const'表示该函数不会修改这个指针指向的内容。
②'const void *b':指向第二个比较的元素。使用'const'表示该函数不会修改这个指针指向的内容。
int int_a = *(int*)a;
int int_b = *(int*)b;
①‘a’和‘b’是‘const void*’类型,因为‘qsort’是通用函数,可以用于任意类型的数据排序。需要将‘ void *’转换成‘int *’,然后解引用以获得实际的整数值。
②(int*)a将'void *'类型的'a'转换为'int * '类型。
③‘ *(int*)a ’解引用‘int *’指针,获取指向的的整数值,并赋值给int_a。
return (int_a > int_b) - (int_a < int_b);
①比较并返回结果:这个表达式使用了布尔值计算:
(int_a > int_b)会产生一个布尔值,如果int_a大于int_b,结果是1,否则是0。
(int_a < int_b)会产生一个布尔值,如果int_a小于int_b,结果是1,否则是0。
②通过减法(int_a > int_b) - (int_a < int_b),可以得到:
如果int_a大于int_b,结果是1 - 0 = 1(正值)。
如果int_a等于int_b,结果是0 - 0 = 0(零)。
如果int_a小于int_b,结果是0 - 1 = -1(负值)。
注意:(int_a > int_b) - (int_a < int_b)该表达式按升序排列,若按降序排列,则为(int_a < int_b)-(int_a > int_b)
2.对'char'类型排序
#include <stdio.h>
#include <stdlib.h>
// 比较函数:比较两个字符
int compare_chars(const void* a, const void* b) {
char char_a = *(char*)a;
char char_b = *(char*)b;
return (char_a > char_b) - (char_a < char_b);
}
int main() {
char arr[] = { 'd', 'b', 'a', 'c', 'e' };
size_t arr_size = sizeof(arr) / sizeof(arr[0]);
// 调用 qsort 进行排序
qsort(arr, arr_size, sizeof(char), compare_chars);
// 打印排序后的数组
for (size_t i = 0; i < arr_size; i++) {
printf("%c ", arr[i]);
}
printf("\n");
return 0;
}
运行结果 :
代码解释:
(1)compare_chars函数:将void指针转换为char指针并解引用,返回两个字符的差值。
(2)main函数:定义字符数组arr,计算数组大小,调用qsort进行排序,最后打印排序后的数组。
3.对结构体类型排序
#include <stdio.h>
#include <stdlib.h>
// 定义一个结构体类型
typedef struct {
int id;
float score;
} Student;
// 比较函数:比较两个结构体,根据分数排序
int compare_students(const void* a, const void* b) {
Student student_a = *(Student*)a;
Student student_b = *(Student*)b;
return (student_a.score > student_b.score) - (student_a.score < student_b.score);
}
int main() {
Student students[] = {
{1, 85.5},
{2, 90.0},
{3, 78.0},
{4, 92.0},
{5, 88.5}
};
size_t arr_size = sizeof(students) / sizeof(students[0]);
// 调用 qsort 进行排序
qsort(students, arr_size, sizeof(Student), compare_students);
// 打印排序后的结构体数组
for (size_t i = 0; i < arr_size; i++) {
printf("ID: %d, Score: %.1f\n", students[i].id, students[i].score);
}
return 0;
}
运行结果:
代码解释:
(1)定义结构体Student,包含id和score两个成员。
(2)compare_students函数:将void指针转换为Student指针并解引用,返回两个学生分数的差值。
(3)main函数:定义学生结构体数组students,计算数组大小,调用qsort进行排序,最后打印排序后的结构体数组。
通过这些示例,可以看到qsort函数如何在C语言中对不同类型的数据进行排序。关键在于提供适当的比较函数来比较数组中的元素。
三、冒泡排序模拟实现qsort
#include<stdio.h>
#include<stdlib.h>
//比较函数指针类型
typedef int (*compare_fun)(const void*, const void*);
//比较函数,比较两个整数
int compare_ints(const void* a, const void* b)
{
int int_a = *(int*)a;
int int_b = *(int*)b;
return (int_a > int_b) - (int_a < int_b);
}
//冒泡排序函数:对数组进行排序(模拟qsort)
void bubble_sort(void* base, size_t nmemb, size_t size, compare_fun compare)
{
char* arr = (char*)base;//将void指针转换为char指针以逐字节操作
int i = 0;
for ( i = 0; i < nmemb - 1; i++)//趟数
{
//一趟内部两两比较
int j = 0;
for (j = 0; j < nmemb - 1 - i; j++)
{
char* current = arr + j * size;//指向当前元素
char* next = arr + (j + 1) * size;//指向下一个元素
if (compare(current, next) > 0)
{
int k = 0;
for (k = 0; k < size; k++)
{
char temp = *(current + k);
*(current + k) = *(next + k);
*(next + k) = temp;
}
}
}
}
}
int main()
{
int arr[] = { 4,2,5,3,1 };
size_t arr_size = sizeof(arr) / sizeof(arr[0]);
//使用冒泡发模拟qsort进行排序
bubble_sort(arr, arr_size, sizeof(int), compare_ints);
//打印排序后的数组
int i = 0;
for (i = 0; i < arr_size; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
代码逻辑梳理:
1. 定义比较函数指针类型 `compare_func` :
`compare_func` 是一个函数指针类型,它指向一个函数,该函数接受两个 `const void* ` 类型的参数,并返回一个整数值。
2. 定义具体的比较函数 `compare_ints` :
`compare_ints` 是一个比较函数,用于比较两个整数。
它满足了 `compare_func` 函数指针类型的要求,接受两个 `const void* ` 类型的参数,并返回一个整数值。
3.定义冒泡排序函数 `bubble_sort` :
(1)`bubble_sort` 函数接受四个参数:数组的起始地址 `base`,数组中元素的个数 `nmemb`,每个元素的大小 `size`,以及一个比较函数指针 `compare`。
(2) 在函数内部,使用冒泡排序算法对数组进行排序。
(3) 每次比较两个元素时,使用 `compare` 函数指针来确定它们的相对顺序。
4. 在 `main` 函数中调用 `bubble_sort` :
(1) 在 `main` 函数中,定义了一个整数数组 `arr`,并计算了数组的大小 `arr_size`。
(2) 调用 `bubble_sort` 函数,将数组 `arr` 的起始地址、数组大小、每个元素的大小和比较函数指针 `compare_ints` 作为参数传递给了 `bubble_sort` 函数。
5. 冒泡排序实现 :
在 `bubble_sort` 函数内部,使用了冒泡排序算法对数组进行排序。每次迭代中,比较相邻的两个元素,根据比较函数指针 `compare` 确定它们的相对顺序,并在需要时交换它们的位置,直到数组完全排序。
6. 打印排序后的数组 :
最后,在 `main` 函数中,通过循环遍历打印了排序后的数组。
通过这个实现,我们实现了一个通用的冒泡排序函数 `bubble_sort`,它可以接受不同类型的比较函数,并对数组进行排序。
解释:!!
在C语言中,函数名实际上就是函数的地址。当我们使用函数名时,编译器会自动将其转换为函数的地址。这意味着我们可以像传递其他变量一样,将函数名作为参数传递给函数。在这种情况下,我们可以将compare_ints函数名作为参数传递给bubble_sort函数。
在bubble_sort函数的参数列表中,compare参数是一个函数指针,它指向一个函数,该函数接受两个const void* 类型的参数,并返回一个整数值。在bubble_sort函数内部,我们使用compare指针来调用这个函数,而不必知道它具体是哪个函数,只需知道它具有与compare_func类型一致的格式即可。
因此,当我们在main函数中调用bubble_sort时,将compare_ints函数名作为参数传递给bubble_sort的compare参数时,实际上是将compare_ints函数的地址传递给了bubble_sort函数,因为函数名本身就代表着函数的地址。