目录
引言:
1. qsort函数简介:
qsort函数原型:
函数参数介绍:
比较函数(compar)的编写:
(补充) void*类型的指针:
2.qsort函数示例:
2.1对int类型排序:
2.2对char类型排序:
2.3对浮点型排序:
2.4对结构体类型进行排序:
3. 模拟实现qsort函数:
结语:
qsort函数是C语言中的一个非常有用的库函数,底层使用的是快速排序的方式,用于对数据进行排序。对数据进行排序的方法有很多,例如:冒泡排序、选择排序、插入排序等,快速排序只是这众多排序方法中的一种。这个函数可以直接使用,并且可以用来排序任意类型的数据。本文将详细介绍qsort函数的使用方法,并模拟实现一个简单的qsort函数。
在学习库函数的过程中,遇到陌生的函数,我们可以通过cplusplus网站来了解它。
void qsort (void* base, size_t num, size_t size,
int (*compar)(const void*,const void*));
比较函数是qsort函数的一个重要参数,它定义了排序的规则。比较函数应满足以下条件:
qsort函数给compar函数规定了特定的参数,所以我们设计cmp函数时要严格遵守其参数设定。需要注意的是:函数的返回结果一定要确保是整型,如果不是一定要强制类型转换成整型。
整型数据的比较 :
int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
浮点型数据的比较:
int cmp_float(const void* e1, const void* e2)
{
return (int)(*(float*)e1 - *(float*)e2);
}
字符串大小的比较:
int cmp_str_size(const void* e1, const void* e2)
{
return strcmp((char*)e1, (char*)e2);
}
字符串长度的比较:
int cmp_str_len(const void* e1, const void* e2)
{
return strlen((char*)e1) - strlen((char*)e2);
}
结构体变量的比较:
int cmp_by_name(const void* e1, const void* e2)
{
return (int)(((stu*)e1)->age - ((str*)e2)->age);
}
对于int*的指针+1跳过一个整型,解引用访问4个字节。char*的指针+1跳过1个字节,解引用访问1个字节。但是对于void*的指针既不能进行解引用操作,也不能进行加减整数的操作,它是一个无具体类型的指针,就像一个“垃圾桶”一样,可以用来存放任意类型数据的地址,使用的时候,只需进行强制类型转换即可。
升序情况:
#include
#include //使用qsort函数需要包含头文件
int cmp_int(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;
}
int main()
{
int arr[] = { 1,3,2,5,4,6,8,7,0,9 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
运行结果:
降序情况:
#include
#include //使用qsort函数需要包含头文件
int cmp_int(const void* e1, const void* e2)
{
return *(int*)e2 - *(int*)e1;
}
int main()
{
int arr[] = { 1,3,2,5,4,6,8,7,0,9 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_int);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
运行结果:
#include
#include //使用qsort函数需要包含头文件
int cmp_char(const void* e1, const void* e2)
{
return *(char*)e1 - *(char*)e2;
}
int main()
{
char arr[] = { 'b','e','f','c','a','d' };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_char);
for (int i = 0; i < sz; i++)
{
printf("%c ", arr[i]);
}
return 0;
}
运行结果:
注意:
在使用qsort函数对浮点型进行排序时,需要使用三目运算符(条件运算符)来定义比较函数的返回值。这是因为浮点数存在精度问题,直接使用减法运算符来比较两个浮点数可能会导致不准确的结果。在比较函数中,返回值为负数表示第一个元素小于第二个元素,返回值为零表示两个元素相等,返回值为正数表示第一个元素大于第二个元素。
#include
#include //使用qsort函数需要包含头文件
int cmp_float(const void* e1, const void* e2)
{
return ((*(float*)e1) > (*(float*)e2) ? 1 : -1);
}
int main()
{
float arr[] = { 1.2, 5.6, 8.7, 3.4, 9.0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_float);
for (int i = 0; i < sz; i++)
{
printf("%.1f ", arr[i]);
}
return 0;
}
运行结果:
#include
#include //使用qsort函数需要包含头文件
#include
struct stu
{
char name[20];
int age;
};
int cmp_age(const void* e1, const void* e2)
{
return ((struct stu*)e1)->age - ((struct stu*)e2)->age;
}
int main()
{
struct stu arr[3] = { {"zhangsan", 20}, {"lisi", 18}, {"wangwu", 36} };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), cmp_age);
for (int i = 0; i < sz; i++)
{
printf("%s %d ", arr[i].name, arr[i].age);
}
return 0;
}
运行结果:
我们今天模拟实现的qsort函数是在冒泡排序的基础上而实现的,那我们先来看一下冒泡排序的实现。
冒泡排序的原理是:从左到右,相邻元素进行比较。每次比较一轮,就会找到序列中最大的一个或最小的一个,这个数就会从序列的最右边冒出来。以从小到大排序为例,第一轮比较后,所有数中最大的那个数就会浮到最右边;第二轮比较后,所有数中第二大的那个数就会浮到倒数第二个位置……就这样一轮一轮地比较,最后实现从小到大排序。
#include
void Buttle_Sort(int arr[], int sz)
{
//共进行sz-1趟
for (int i = 0; i < sz - 1; i++)
{
//每一趟
for (int 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;
}
}
}
}
int main()
{
int arr[] = { 2,4,3,5,6,1,7,9,8,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
Buttle_Sort(arr, sz);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}
下面我们要做的就是改造冒泡排序,使之成为可以排序任意类型的数组的函数,以整型数组为例:
#include
void swap(char* p1, char* p2, int width)
{
for (int i = 0; i < width; i++) //不知道是什么类型,所以要一个字节一个字节来进行交换
{
char temp = *p1;
*p1 = *p2;
*p2 = temp;
p1++;
p2++;
}
}
int compare(const void* p1, const void* p2)
{
return *((int*)p1) - *((int*)p2);
}
//void* base - 要求排序不同类型的数组,void*恰好能接收任意类型的数据
//int num - 元素个数
//int width - 一个元素的大小
//int (*compare)(const void* p1, const void* p2) 函数传参函数指针接收
int bubble_qsort(void* base, int num, int width,int (*compare)(const void* p1, const void* p2)))
{
for (int i = 0; i < num - 1; i++)
{
for (int j = 0; j < num - 1 - i; j++)
{
//强制类型转化为char*型的数据,是因为一开始不知道数组的类型
//如果要访问数据的话,只能一个字节一个字节的访问
//这样有利于排序各种类型的数
if (compare((char*)base + j * width,(char*)base + (j + 1) * width) > 0)
{
//写一个Swap函数来交换
swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
}
}
}
}
int print(int arr[], int num)
{
for (int i = 0; i < num; i++)
{
printf("%d ", arr[i]);
}
}
int main()
{
int arr[10] = { 5,7,9,1,3,4,6,8,2,0 };
int num = sizeof(arr) / sizeof(arr[0]);//计算数组中的元素个数
//打印排序前的数组
printf("排序前为:");
print(arr, num);
printf("\n");
bubble_qsort(arr, num, sizeof(arr[0]), compare);
//打印排序后的数组
printf("排序后为:");
print(arr, num);
return 0;
}
运行结果:
在上面的程序中,我们首先定义了一个swap函数,用于交换两个元素的值。然后,我们定义了一个bubble_qsort函数来实现冒泡排序算法。在bubble_qsort函数中,我们使用两个嵌套的循环来遍历数组,并调用compare函数来比较相邻的元素。如果比较函数返回的结果大于0,说明当前元素需要交换位置,我们就调用swap函数来实现交换。通过多次遍历和交换,我们可以将数组中的元素按照指定的比较规则进行排序。在main函数中,我们定义了一个待排序的整型数组,并调用bubble_qsort函数来对其进行排序。最后,我们打印排序后的数组,输出结果为:0 1 2 3 4 5 6 7 8 9,即为排序后的数组。
本文详细介绍了qsort函数的使用方法,并模拟实现了一个简单的qsort函数。通过使用qsort函数,我们可以方便地对各种类型的数组进行排序。如果觉得本篇文章对大家有所帮助,不妨一键三连支持一下博主,蟹蟹!