当前位置:网站首页>【C语言】库函数qsort的使用
【C语言】库函数qsort的使用
2022-06-22 15:16:00 【蒋灵瑜的流水账】


一、回调函数
C语言库函数中的qsort的是一个回调函数,回调函数就是一个通过函数指针调用的函数。如果把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
二、库函数qsort

void* base:要排序的数据的起始位置
size_t num:待排序数据的元素个数
size_t width:待排序的数据元素的大小,单位是字节
int(__cdecl*compare)(constvoid*elem1,constvoid*elem2):把比较函数的地址传给cmp,e1和e2是要比较的两个元素的地址。(__cdecl是函数调用约定)
注意:最后一个函数参数是一个函数指针,所以在调用库函数qsort()的时候,传的参数是比较函数的地址。

1、e1小于e2,返回值小于0;
2、e1等于e2,返回0;
3、e1大于e2,返回值大于0。
三、使用qsort排序整型数组
#include <stdlib.h>
#include <stdio.h>
int int_cmp(const void* e1, const void* e2)
{
return *(int*)e1 - *(int*)e2;//升序排序
}
int main()
{
int arr[10] = { 9,8,7,6,5,2,4,3,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort(arr, sz, sizeof(arr[0]), int_cmp);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);//打印0 1 2 3 4 5 6 7 8 9
}
return 0;
}库函数qsort的比较函数是需要自己实现的,并且已经给定了比较函数的两个形参。因为e1和e2是无类型指针,不能解引用和作加减。所以此处使用时需要先将指针类型强制类型转换为int*,再进行解引用操作。
此处可以加深回调函数的理解:int_cmp是本人来实现的,当程序运行到qsort函数时,由库函数qsort对int_cmp进行调用。这就是回调函数。
四、使用qsort排序结构体
1、使用qsort排序结构体中的字符成员

先创建一个学生的结构体类型,定义一个结构体类型的学生数组,数组内包含3名学生的信息。通过qsort函数进行排序。在实现str_name_cmp函数时,需要先将e1和e2先强制类型转换为struct Stu*类型,由于strcmp函数的返回值刚好契合str_name_cmp函数,可以直接使用return将返回值带回。通过打印可以发现三名同学已经按ASCII码完成排序。
2、使用qsort排序结构体中的整型成员
#include <stdlib.h>
#include <stdio.h>
struct Stu
{
char name[20];
int age;
};
int str_age_cmp(const void* e1, const void* e2)
{
return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}
int main()
{
struct Stu s[] = { {"zhangsan",18},{"lisi",17},{"wangwu",22} };
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), str_age_cmp);
for (int i = 0; i < sz; i++)
{
printf("%d ", s[i].age);//输出17 18 22
}
return 0;
}排序结构体整型成员和排序整型数组、结构体字符成员方式相似。
五、基于冒泡排序的库函数qsort的模拟实现
1、使用改写函数排序整型数组
#include <stdlib.h>
#include <stdio.h>
int int_cmp(const void* e1, const void* e2)//比较函数
{
return *(int*)e1 - *(int*)e2;//升序排序
}
Swap(char* p1, char* p2, size_t width)
{
for (int i = 0; i < width; i++)//每个字节交换
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2++;
}
}
void qsort_bubble(void* base, size_t sz, size_t width, int(* compare)(const void* e1, const void* e2))
{//基于库函数qsort进行改写的冒泡排序
for (int i = 0; i < sz-1; i++)
{
int change = 0;
for (int j = 1; j < sz - i; j++)
{
//交换
if (compare((char*)base+(j-1)*width , (char*)base+j*width)>0)
{
Swap((char*)base + (j - 1) * width, (char*)base + j * width,width);
change = 1;
}
}
if (change == 0)
break;
}
}
int main()
{
int arr[10] = { 9,8,7,6,5,2,4,3,1,0 };
int sz = sizeof(arr) / sizeof(arr[0]);
qsort_bubble(arr, sz,sizeof(arr[0]),int_cmp);
for (int i = 0; i < sz; i++)
{
printf("%d ", arr[i]);
}
return 0;
}qsort_bubble函数中,采用冒泡排序的比较方式,形参模仿库函数qsort中的形参。
在函数内部调用compare时(compare是比较函数的地址),由于外部比较的数据类型不可知,故使用最小内置类型char和数据类型的长度width来表示外部类型所占字节。
2、使用改写函数排序结构体中的字符成员
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
struct Stu//定义结构体
{
char name[20];
int age;
};
int str_name_cmp(const void* e1, const void* e2)//字符的比较函数
{
return strcmp(((struct Stu*)e1)->name, ((struct Stu*)e2)->name);
}
Swap(char* p1, char* p2, size_t width)//交换函数
{
for (int i = 0; i < width; i++)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
p1++;
p2++;
}
}
void qsort_bubble(void* base, size_t sz, size_t width, int(*compare)(const void* e1, const void* e2))
{基于库函数qsort进行改写的冒泡排序
for (int i = 0; i < sz - 1; i++)
{
int change = 0;
for (int j = 1; j < sz - i; j++)
{
if (compare((char*)base + (j - 1) * width, (char*)base + j * width)>0)
{
Swap((char*)base + (j - 1) * width, (char*)base + j * width, width);
change = 1;
}
}
if (change == 0)
break;
}
}
int main()
{
struct Stu s[] = {
{"zhangsan",18},{"lisi",17},{"wangwu",22}};
int sz = sizeof(s) / sizeof(s[0]);
qsort(s, sz, sizeof(s[0]), str_name_cmp);
for (int i = 0; i < sz; i++)
{
printf("%s ", s[i].name);
}
return 0;
}输出结果lisi wangwu zhangsan,理解方式和上方例子一样。
3、对库函数qsort的总结
第一次使用库函数qsort的时候,肯定会疑惑,为什么e1-e2的返回值大于0时,升序排序;反之降序?
我们在模拟实现的时候,在冒泡排序内部调用compare这个函数地址,传参时,如果前一个元素的值大于后一个元素,那么传入比较函数,e1-e2>0,进行交换,交换完毕后e1<e2,实现了升序排序!
如果要实现降序排序,在比较函数内使用e2-e1即可,意思是后一个元素大于前一个元素,进行交换,交换完毕后e1>e2,实现了降序排序!
六、力扣977#中库函数qsort的使用

使用pow函数对数组元素逐个平方。由于素组内存在负数,所以平方后数组可能乱序,需要重新排序,这里可以使用库函数qsort进行排序。
int compare(const void* elem1,const void* elem2)//比较函数
{
return *(int*)elem1-*(int*)elem2;
}
int* sortedSquares(int* nums, int numsSize, int* returnSize){
*returnSize=numsSize;
for(int i=0;i<numsSize;i++)
{
nums[i]=pow(nums[i],2);
}
qsort(nums,numsSize,sizeof(nums[0]),compare);//库函数qsort的使用
return nums;
}但是平常刷题是还是不建议无脑上qsort,需要根据题目要求合理的选择排序算法。
边栏推荐
- Prometheus监控之Consul监控 [consul-exporter]
- CUMT学习日记——数字图像处理考试速成笔记
- SAP ABAP sub screen tutorial: call sub screen -010 in SAP
- User exit and customer exit in SAP ABAP -015
- Adding an unknown type of MCU to jflash
- 数睿数据深度 | 关于软件自主可控,源代码向左,无代码向右
- 知识管理在业务中的价值如何体现
- 【山大会议】私人聊天频道 WebRTC 工具类
- '不敢去怀疑代码,又不得不怀疑代码'记一次网络请求超时分析
- CMake教程系列-00-简介
猜你喜欢

POD 类型

Basic knowledge of audio and video | analysis of ANS noise suppression principle

SAP ABAP data types, operators and editors-02

【山大会议】应用设置模块

在JFlash中添加未知类型的单片机

数睿数据荣获第二届ISIG中国产业智能大会两项年度大奖

Navicat premium connecting to Oracle database (Graphic tutorial)

什么是 SAP ABAP? 类型、ABAP 完整形式和含义

ABAP query tutorial in sap: sq01, sq02, sq03-017

ironSource Luna 推出苹果搜索广告限时优惠,注册即享3个月免费服务
随机推荐
odoo系统对原有模型单独开发的视图设置优先级
买网红雪糕的我,成了大冤种
学习量子纠缠的可解释表示,该深度生成模型可直接应用于其他物理系统
Swift -- save print log to sandbox
Dear students, don't read the textbooks any more. Just read this one for the complexity of time
Solve the problem of MySQL remote login permission
安全信得过!天翼云数据安全管理平台通过评测
十九、Xv6上下文切换(上下文切换的实现;状态机的封装与恢复)
SAP ABAP data types, operators and editors-02
6.gui (graphics, filling)
IO模型的5中模式
Default function control =default and =delete
[Shanda conference] application setting module
shell学习
nio编程service
Gbase "library" special training of innovation and application Committee of Beijing fintech Industry Alliance
Deploy odoo to the server and configure it as a service
SAP value process & help request process-011
SAP 中的 ABAP 查询教程:SQ01、SQ02、SQ03-017
Mysql触发器