企业的营销型网站建设,网站维护费一年多少钱,全国工程信息平台官网,彩票app软件大全前言#xff1a;对于库函数有适当了解的朋友们#xff0c;对于 qsort 函数想必是有认知的#xff0c;因为他可以对任意数据类型进行排序的功能属实是有点厉害的#xff0c;本次分享#xff0c;笔者就给大家带来 qsort 函数的全面的解读 本次知识的分享笔者分为上下俩卷文章… 前言对于库函数有适当了解的朋友们对于 qsort 函数想必是有认知的因为他可以对任意数据类型进行排序的功能属实是有点厉害的本次分享笔者就给大家带来 qsort 函数的全面的解读 本次知识的分享笔者分为上下俩卷文章进行讲解在本篇文章中给大家带来 qsort 函数的函数内部构造解析以及如何通过冒泡排序模拟实现 qsort 的函数功能 上卷深入解析 qsort 排序上它为什么是万能排序 目录
一.模拟实现函数参数
二.确定算法大体的框架
三.实现函数的判断逻辑、
函数指针部分
具体判断方法函数
四.交换函数的实现
代码实现
五.完整功能测试
六.完整代码 一.模拟实现函数参数
首先我们打开 cplusplus 官网查看 qsort 的参数要求和含义 qsort - C Reference (cplusplus.com) 具体参数信息如下 void* base待排序数组的第一个元素的地址size_t num待排序数组的元素个数size_t size待排序数组中一个元素的大小int (*compar)(const void*, const void*)函数指针-cmp指向了一个函数这个函数是用来比较两个元素的e1和e2中存放的是需要比较的两个元素的地址 根据上面的定义说明我们对函数参数进行模拟
void my_qsort(void* base, size_t num, size_t size, int (*compare)(const void* e1, const void* e2))
二.确定算法大体的框架 正如标题所说笔者这里使用较为容易理解的冒泡排序当然其他的快速排序选择排序堆排序希尔排序等算法都是可以使用的笔者这里只是为了方便讲解具体实现流程和细节所以选择的冒泡排序的算法 在选择好了使用什么算法进行模拟实现后我们就需要来设计大体的框架了首先我们列出一般冒泡排序的形式然后在这基础上进行删改 for (int i 0; i num - 1; i){//每一趟for (int j 0; j num - i - 1; j){//排序前一个元素大于后一个就进行交换if (arr[j] arr[j 1]){int temp 0;temp arr[j];arr[j] arr[j 1];arr[j 1] temp;}}} 在这里我们需要修改的地方主要是俩点 判断部分考虑到不同数据的复杂类型判断部分不能再使用这样简单数组的方式进行判断应该设计成一个函数指针针对不同的数据类型调用不同的函数来进行不同的判断交换部分 考虑不同的数据的复杂类型交换部分也不能使用 int 型的临时变量来进行交换数据应该设计成对任意数据类型都能交换的方式也就是对字节直接进行操作对于不同的数据类型我们直接对其内存存储的字节进行交换这样就能达到目的和要求 三.实现函数的判断逻辑、
函数指针部分 首先为了实现不同的判断方法我们要有一个函数指针去调用不同的判断方法我们根据 qsort 的参数要求设计如下函数指针
int (*compare)(const void* e1, const void* e2) 这个函数指针有俩个参数分别代表着需要判断排序的数据我们调用的参数的返回值是有要求的如下图 那我们就可以将这个判断逻辑的函数的返回值来作为 if 语句判断依据实现实例如下
if (compare((char*)base j * size, (char*)base (j 1) * size) 0)
{} 这代表着如果判断函数返回值大于0那我们就执行交换操作如果等于0或者小于0就不执行交换操作那我们实现了函数调用的接口我们还得具体的实现判断逻辑函数方便进行调用
具体判断方法函数 根据我们在上卷文章中讲解的判断逻辑和实现方法我们可以同样试用在这里具体细节如有不懂可以访问下面的链接 深入解析 qsort 排序上它为什么是万能排序 //比较函数--整形
int comp_int(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}//比较函数--浮点型
int comp_float(const void* a, const void* b)
{return *(float*)b - *(float*)a;
}//比较函数--按照年龄
int comp_age(const void* a, const void* b)
{return ((struct stu*)b)-age - ((struct stu*)a)-age;
}//比较函数--按照姓名
int comp_name(const void* a, const void* b)
{return strcmp(((struct stu*)a)-name, ((struct stu*)b)-name);
}四.交换函数的实现 首先我们要确定我们要进行交换的对象对于冒泡排序来说需要交换的只是前后俩个元素那我们拿到他们的地址就可以进行交换了我们具体实现如下
//交换
swap((char*)base j * size, (char*)base (j 1) * size, size);
这里分别对三个参数进行一下解释 (char*)base j * size 确定要交换的第一个数据的地址(char*)base (j 1) * size 确定要交换的第二个数据的地址size 确定这俩个数据直接隔了多少个字节方便逐字节进行操作 对于参数为什么这样设定有小伙伴可能不理解下面笔者就以 int 类型举例我们知道int 类型占 4 个字节而 char* 指针解引用可以访问一个字节而数据在内存中存储的最小字节都是 1 个字节那我们就可以 通过 char* 指针来逐个访问字节就像下面这张图一样我们逐个交换俩个数据中的每一个字节在交换完成后我们就相当于把这俩个数字进行了交换 在逐个交换字节后宏观上给我们的感受就是直接交换了我们的数据内容也就是说我们使用俩个 char* 指针分别访问要交换的俩个在数据每一次交换一个字节后指针加一我们就可以继续访问交换后面的字节在这里循环往复交换 size 个字节后这俩个数据就被我们完全交换了 代码实现 注意在具体写代码的过程中不要非法访问空间在下方代码的注释部分笔者对错误代码进行了注释大家在写过程中一定得注意在指针访问一些只读区域或者不是我们申请的空间的区域就会出现段错误就像注释部分的代码我们定义一个空指针然后再对这个空指针进行解引用访问赋值的操作就会出现报错
//交换函数
void swap(char* buf1, char* buf2, size_t size)
{//逐个字节进行交换一共有size个字节for (int i 0; i size; i){//错误示范//char* temp 0;//*temp *buf1;//*buf1 *buf2;//*buf2 *temp;//buf1;//buf2;//正确示范char temp *buf1;*buf1 *buf2;*buf2 temp;buf1;buf2;}
}
五.完整功能测试 我们仍然使用在上篇文章中的用例进行测试观察我们设计的函数能不能完成我们预期的功能在这里对整形数组浮点型数组结构体数组进行测试
int main()
{int arr1[] { 9,8,7,6,5,4,3,2,1,0 };int sz sizeof(arr1) / sizeof(arr1[0]);print1(arr1);my_qsort(arr1, sz, sizeof(int), comp_int);print1(arr1);float arr2[5] { 1.2,3.4,5.6,7.8,9.9 };print2(arr2);my_qsort(arr2, 5, sizeof(float), comp_float);print2(arr2);struct stu arr3[] { {zhangsan,19},{lisi,20},{wangswu,21} };my_qsort(arr3, 3, sizeof(arr3[0]), comp_name);my_qsort(arr3, 3, sizeof(arr3[0]), comp_age);system(pause);return 0;
} 观察结果 我们可以发现和我们预期的一样对于不同数据类型我们自己模拟的函数都可以实现排序功能 六.完整代码
#define _CRT_SECURE_NO_WARNINGS 1
#includestdio.h
#includestring.h
#includewindows.h//结构体
struct stu
{char name[20];int age;
};void print1(int* arr)
{for (int i 0; i 10; i){printf(%d , *(arr i));}printf(\n);
}void print2(float* arr)
{for (int i 0; i 5; i){printf(%.2f , *(arr i));}printf(\n);
}//比较函数--整形
int comp_int(const void* e1, const void* e2)
{return *(int*)e1 - *(int*)e2;
}//比较函数--浮点型
int comp_float(const void* a, const void* b)
{return *(float*)b - *(float*)a;
}//比较函数--按照年龄
int comp_age(const void* a, const void* b)
{return ((struct stu*)b)-age - ((struct stu*)a)-age;
}//比较函数--按照姓名
int comp_name(const void* a, const void* b)
{return strcmp(((struct stu*)a)-name, ((struct stu*)b)-name);
}//交换函数
void swap(char* buf1, char* buf2, size_t size)
{//逐个字节进行交换一共有size个字节for (int i 0; i size; i){//错误示范//char* temp 0;//*temp *buf1;//*buf1 *buf2;//*buf2 *temp;//buf1;//buf2;//正确示范char temp *buf1;*buf1 *buf2;*buf2 temp;buf1;buf2;}
}//void qsort(void* base, size_t num, size_t size,int (*compar)(const void*, const void*));
void my_qsort(void* base, size_t num, size_t size, int (*compare)(const void* e1, const void* e2))
{//使用冒泡排序for (int i 0; i num - 1; i){//每一趟for (int j 0; j num - i - 1; j){//排序前一个元素大于后一个if (compare((char*)base j * size, (char*)base (j 1) * size) 0){//交换swap((char*)base j * size, (char*)base (j 1) * size, size);}}}
}int main()
{int arr1[] { 9,8,7,6,5,4,3,2,1,0 };int sz sizeof(arr1) / sizeof(arr1[0]);print1(arr1);my_qsort(arr1, sz, sizeof(int), comp_int);print1(arr1);float arr2[5] { 1.2,3.4,5.6,7.8,9.9 };print2(arr2);my_qsort(arr2, 5, sizeof(float), comp_float);print2(arr2);struct stu arr3[] { {zhangsan,19},{lisi,20},{wangswu,21} };my_qsort(arr3, 3, sizeof(arr3[0]), comp_name);my_qsort(arr3, 3, sizeof(arr3[0]), comp_age);system(pause);return 0;
} 本次分享的俩篇文章就到此为止啦希望我的分享对您有所帮助文章中如有错误欢迎积极指正您的认可就是我最大的动力那我们下次分享再见