摘要:一前言我们学习过的冒泡排序,插入排序,选择排序等经典排序方法,为我们数据排序提供了稳定思路,但局限在于排序数据类型的单一。
我们学习过的冒泡排序,插入排序,选择排序等经典排序方法,为我们数据排序提供了稳定思路,但局限在于排序数据类型的单一。为了解决这一问题,c语言中提供了库函数qsort解决。我们今天就通过自定义函数实现qsort的功能,排序方法采用基本的冒泡排序
我们需要传入四个变量:base——待排序数组的首元素地址;
num——数组内的元素个数;
width——每个元素的大小(单位为字节);
函数指针——传入两个数的地址,比较二者大小(需自己设计)
1.可以传入任何类型的指针而不会报警告,适合我们实现任何数据类型排序的目的;
2.不可以对其进行解引用操作,除非通过强制类型转换()确定其具体类型;
3.不可以对其进行加减运算,原因是不知道类型所以不知道步长,因此还是需要强制类型转换
注意:都需要先进行强制类型转换才可以解引用
int cmp_int(const void* e1, const void* e2){ return *(int*)e1 - *(int*)e2;}
char类型数据不可以用<>=进行比较,所以要用函数strcmp库函数,头文件为#include
int cmp_char(const void*e1, const void*e2){ return strcmp((char*)e1, (char*)e2);}
因为返回的是int类型,所以我们加入了判断语句。用数的正负表示数的大小情况
int cmp_float(const void*e1, const void*e2){ if ((float*)e1 > (float*)e2) return 1; else if ((float*)e1 ==(float*)e2) return 0; else return -1;}
结构体数组元素不可以直接比较,必须先选出结构体某一内容进行比较
typedef struct book{ char name[20]; int prince; }b;//重命名struct book为bint cmp_stru_price(const void*e1, const void*e2){ return ((b*)e1)->prince - ((b*)e2)->prince;}
注意!!!(b*)e1外面的括号不可以省略,因为->的优先级比强制类型转换高
首先思考一个问题:既然传入的指针为void*类型,如何实现步长的确定?聪明的科学家想到利用width作为我们的标准
void bubble_sort(void*base,int sz,int width,int(*cmp)(void*,void*)){ int i; int j; for (i = 0; i < sz - 1; i++) { for (j = 0; j < sz - 1-i; j++) { if (cmp((char*)base + width*j, (char*)base + width*(j + 1))>0) { swap((char*)base + width*j, (char*)base + width*(j + 1),width); } } }}
1.int(*)(void*,void*)是一个函数指针,指向我们之前设计的大小比较函数
2.在使用base的时候要先强制类型转换才可以作加减运算
3.漂亮的地方在于,不管实际传入的base是什么类型,我们都将其转化为char*类型的指针,因为char*的步长最小为1,加上width就可以准确指向下一个
以int为例,width为4,所及就可以指向下一个元素
void swap(char*buff1,char*buff2,int width){ int i; for (i = 0; i < width; i++) { int tmp = *buff1; *buff1 = *buff2; *buff2 = tmp; buff1++; buff2++; }}
值得关注的是,交换不是一次就可以了,因为我们现在是char*类型的指针,如上图所画,一次只能交换一格,如交换int的,要交换4次
1.函数指针的使用,使我们每次只需导入大小比较函数的地址即可,而不必写多个函数,分别含有不同的大小比较函数,减少了重复代码的出现
2.width的使用相当于告诉了我们进行比较的数组元素的类型,满足我们实现各种数据类型排序的需求
3.void*函数海纳百川,方便了我们的输入,只是注意在使用时的强制类型转化,否则无法使用
希望上述的总结对大家的理解有帮助,也更好的欣赏回调函数(这里为用函数指针调用函数)的魅力。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/118801.html
摘要:故使用无具体类型,又称通用类型,即可以接收任意类型的指针,但是无法进行指针运算解引用,整数等。求指针所占字节而不是解引用访问权限大小。数组就是整个数组的大小,数组元素则是数组元素的大小,指针大小都为。 ...
摘要:参数含义上图是函数各个参数的含义,让我们一个个来看。使用方式头文件要使用函数我们首先需要引用一个头文件的实现函数给函数规定了特定的参数。因此我们设计函数时要严格遵守其参数设定。 目录 1.参数含义 1.首元素地址base 2.元素个数num 3.元素大小size 4.自定义比较函数compa...
摘要:回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。 目录 前言无类型指针结构体指针枚举变量指针函数...
摘要:如果你把函数的指针地址作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。 ...
阅读 3366·2021-09-22 15:17
阅读 2706·2021-09-02 15:15
阅读 1688·2019-08-30 15:54
阅读 1983·2019-08-30 14:02
阅读 2484·2019-08-29 16:58
阅读 2967·2019-08-29 16:08
阅读 1292·2019-08-26 12:24
阅读 1639·2019-08-26 10:41